Merge branch '3.4-dev' into 3.5-dev
diff --git a/.asf.yaml b/.asf.yaml
new file mode 100644
index 0000000..178eb48
--- /dev/null
+++ b/.asf.yaml
@@ -0,0 +1,11 @@
+github:
+  description: "Apache TinkerPop - a graph computing framework"
+  homepage: https://tinkerpop.apache.org/
+  labels:
+    - tinkerpop
+    - gremlin
+    - graph
+    - graphdb
+    - graph-database
+    - gremlin-server
+    - apache
\ No newline at end of file
diff --git a/.dependabot/config.yml b/.dependabot/config.yml
new file mode 100644
index 0000000..0871a00
--- /dev/null
+++ b/.dependabot/config.yml
@@ -0,0 +1,10 @@
+version: 1
+update_configs:
+  - package_manager: "java:maven"
+    directory: "/"
+    update_schedule: "monthly"
+    allowed_updates:
+      - match:
+          update_type: "security"
+      - match:
+          dependency_name: "org.apache.tinkerpop:die-dependabot"
diff --git a/.gitignore b/.gitignore
index 413db57..33731d8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,7 @@
 .classpath
 .project
 .settings
+.factorypath
 _bsp/
 doc/out
 docs/*.asciidoc
@@ -35,5 +36,5 @@
 *nupkg
 NuGet.Config
 nuget*.exe
+BenchmarkDotNet.Artifacts/
 /Dockerfile
-docs/gremlint/
diff --git a/.travis.yml b/.travis.yml
index 1e42d97..b8b02a7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,9 +2,9 @@
 os:
   - linux
 jdk:
-  - openjdk8
+  - openjdk11
 sudo: required
-dist: xenial
+dist: bionic
 services:
   - docker
 cache:
@@ -36,12 +36,13 @@
   - sudo apt install python3.6
   - sudo rm /usr/bin/python3
   - sudo ln -s python3.6 /usr/bin/python3
+  - sudo apt install gcc python3.6-dev libkrb5-dev
 
 jobs:
   include:
     - stage: "tests"
       script: "mvn clean install -Dci --batch-mode -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn"
-      name: "mvn clean install"
+      name: "mvn clean install - jdk11"
     - script: "touch gremlin-dotnet/src/.glv && touch gremlin-dotnet/test/.glv && mvn clean install -q -DskipTests -Dci && mvn verify -pl :gremlin-dotnet,:gremlin-dotnet-tests -P gremlin-dotnet"
       name: ".net"
     - script: "touch gremlin-python/.glv && mvn clean install -q -DskipTests -Dci && mvn verify -pl gremlin-python"
@@ -49,11 +50,20 @@
     - script: "mvn clean install -q -DskipTests -Dci && mvn verify -pl :gremlin-javascript"
       name: "javascript"
     - script:
-      - "mvn clean install -q -DskipTests -Dci"
-      - "mvn verify -pl :gremlin-server -DskipTests -DskipIntegrationTests=false -DincludeNeo4j"
+        - "mvn -version"
+        - "mvn clean install -Dci --batch-mode -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn"
+      jdk: openjdk8
+      name: "mvn clean install - jdk8"
+    - script:
+        - "mvn clean install -q -DskipTests -Dci"
+        - "mvn verify -pl :gremlin-server -DskipTests -DskipIntegrationTests=false -DincludeNeo4j"
       name: "gremlin server"
     - script:
         - "mvn clean install -q -DskipTests -Dci"
+        - "mvn verify -pl :gremlin-server -DskipTests -DskipIntegrationTests=false -DincludeNeo4j -DtestUnified=true"
+      name: "gremlin server - unified"
+    - script:
+        - "mvn clean install -q -DskipTests -Dci"
         - "mvn verify -pl :gremlin-console -DskipTests -DskipIntegrationTests=false"
       name: "gremlin console"
     - script:
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 46fdeb1..7dc6a47 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -16,6 +16,335 @@
 ////
 = TinkerPop3 CHANGELOG
 
+== TinkerPop 3.5.0 (The Sleeping Gremlin: No. 18 Entr'acte Symphonique)
+
+image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/images/gremlin-sleeping-beauty.png[width=185]
+
+[[release-3-5-1]]
+=== TinkerPop 3.5.1 (Release Date: NOT OFFICIALLY RELEASED YET)
+
+
+
+[[release-3-5-0]]
+=== TinkerPop 3.5.0 (Release Date: May 3, 2021)
+
+This release also includes changes from <<release-3-4-11, 3.4.11>>.
+
+* Changed transport implementation to use AIOHTTP instead of Tornado for gremlin-python.
+* Added max_content_length and unit test for it in gremlin-python.
+* Removed compression_option support for transport in gremlin-python.
+* Fixed event loop issues and added unit test for it in gremlin-python.
+* Fixed DriverRemoteConnection multithreading issues and added unit test for it in gremlin-python.
+* Fixed heartbeat timeout issues and tested with local server manually for gremlin-python.
+* Fixed build errors emitted for gremlin-python (asyncio task destroyed but is pending error).
+* Added `gremlin-language` module.
+* Allowed the possibility for the propagation of `null` as a `Traverser` in Gremlin.
+* Added a fully shaded version of `gremlin-driver`.
+* Exposed websocket connection status in JavaScript driver.
+* Fixed a bug where spark-gremlin was not re-attaching properties when using `dedup()`.
+* Fixed a bug in `WsAndHttpChannelizer` pipeline configuration where failed object aggregation could not write back HTTP responses.
+* Ensured better consistency of the use of `null` as arguments to mutation steps.
+* Added a `ResponseStatusCode` to indicate that a client should retry its request.
+* Added `TemporaryException` interface to indicate that a transaction can be retried.
+* Prevented `TraversalStrategy` instances from being added more than once, where the new instance replaces the old.
+* Improved error message for `addE()` when the `from()` or `to()` does not resolve to a `Vertex`.
+* Improved error message for `addE()` when cardinality is specified on `property()` assignments.
+* Allowed `property(T.label,Object)` to be used if no value was supplied to `addV(String)`.
+* Dropped support for .NET Standard 1.3 in Gremlin.Net. Only .NET Standard 2.0 is supported starting with this version.
+* Added GraphBinary support for .NET.
+* Added `UnifiedChannelizer` which exposes HTTP and Websockets connections and processes both sessionless and in-session requests with the same `gremlinPool`.
+* Bounded the `gremlinPool` in Gremlin Server to enforce rate limiting which will then produce a `TOO_MANY_REQUESTS` response status code.
+* Switched from `Newtonsoft.Json` to `System.Text.Json` as the JSON library for Gremlin.Net.
+* Allowed additional arguments to `Client.submit()` in Javascript driver to enable setting of parameters like `scriptEvaluationTimeout`.
+* Gremlin.Net driver no longer supports skipping deserialization by default. Users can however create their own `IMessageSerializer` if they need this functionality.
+* Supported deserialization of `dict` and `list` as a key in a `dict` for Python.
+* Changed the aliased `Client` to proxy `close()` methods to its underlying client.
+* Added support for remote `g.tx()` usage.
+* Added support for bytecode-based sessions.
+* Added a `Graph.Feature` for `supportsNullPropertyValues`.
+* Modified `TokenTraversal` to support `Property` thus `by(key)` and `by(value)` can now apply to `Edge` and meta-properties.
+* Added `SeedStrategy` to allow deterministic behavior for `coin()`, `sample()` and `Order.shuffle`.
+* Added `Grouping` step interface.
+* Added `TraversalParent.replaceTraversal()` which can replace a direct child traversal.
+* Added `ByModulatorOptimizationStrategy` which replaces certain standard traversals w/ optimized traversals (e.g. `TokenTraversal`).
+* Improved `IdentityRemovalStrategy` by accounting for `EndStep` situations.
+* Added `IdentityRemovalStrategy` to the standard list of `TraversalStrategies`.
+* Modified `PathRetractionStrategy` to leave labels more often with `match()` cases to return more consistent results.
+* Refactored `MapStep` to move its logic to `ScalarMapStep` so that the old behavior could be preserved while allow other implementations to have more flexibility.
+* Modified TinkerGraph to support `null` property values and can be configured to disable that feature.
+* Modified `null` handling in mutations to be consistent for a new `Vertex` as well as update to an existing one.
+* Enforced use of anonymous child traversals.
+* Removed support for Python 2.x in gremlinpython.
+* Upgraded to Apache Commons Configuration2.
+* Renamed `StoreStep` to `AggregateLocalStep`.
+* Renamed `AggregateStep` to `AggregateGlobalStep`.
+* Renamed `SERVER_ERROR_SCRIPT_EVALUATION` to `SERVER_ERROR_EVALUATION` given that this response code applies to remote traversals as well as scripts.
+* Refactored `TraversalStrategies` to implement `Iterable`.
+* Refactored `Traversal` semantics to always expect `EmptyStep` as a parent if it is meant to be the root `Traversal`.
+* Configured GraphBinary as the default binary serialization format for the Java Driver.
+* Configured GraphSON 3.0 as the default text serialization format when no serializer can be determined.
+* Configured GraphSON 3.0 as the default setting for the `GraphSONMapper`.
+* Added `JavascriptTranslator` for Java.
+* Added `DotNetTranslator` for Java.
+* Added Groovy `Translator` for Python.
+* Fixed bug in `PythonTranslator` for processing `TraversalStrategy` instances in GraphBinary.
+* Fixed bug in bytecode `Bindings` where calling `of()` prior to calling a child traversal in the same parent would cause the initial binding to be lost.
+* Migrated from Tornado to AIOHTTP for gremlinpython.
+* Bumped to Neo4j 3.4.11.
+* Bumped to Spark 3.0.0.
+* Bumped to Jackson 2.11.x.
+* Supported build for Java 11.
+* Added `MessageSerializer.getMapper()` to return the underlying object that handles serialization for a particular implementation.
+* Added a parameterized `TypeTranslator` for use with `GroovyTranslator` that should produce more cache hits.
+* Added support for `TextP` in Neo4j using its string search functions.
+* Added a kerberos KDC to the docker container for testing GLV's.
+* Added kerberos authentication to Gremlin-Python.
+* Added audit logging to bytecode-based traversals.
+* Changed `TraversalStrategy` application methodology to apply each strategy in turn to each level of the traversal hierarchy starting from root down to children.
+* Added a VertexProgramRestrictionStrategy.
+* Prevented more than one `Client` from connecting to the same Gremlin Server session.
+* Changed the Groovy to an optional dependency in `gremlin-driver`.
+* Added support for configuring an `Authorizer` implementation to Gremlin Server, allowing for authorization of individual gremlin requests.
+* Added `gremlint` module to house the Gremlin query formatting JavaScript library powering gremlint.com.
+* Removed internal functionality for the session close message in Gremlin Server - the message is accepted but ignored if sent.
+* Removed `Property.Exceptions.propertyValueCanNotBeNull` exception type as `null` now has meaning in Gremlin.
+* Removed the "experimental" support for multi/meta-properties in Neo4j.
+* Removed Gryo serialization configurations from Gremlin Server sample configurations and default configurations.
+* Removed previously deprecated custom keep-alive functionality in the Java driver.
+* Removed previously deprecated `BytecodeUtil`.
+* Removed previously deprecated `Cluster.maxWaitForSessionClose` configuration option.
+* Removed previously deprecated `TraversalStrategies.applyStrategies()`.
+* Removed previously deprecated `scriptEvaluationTimeout`.
+* Removed previously deprecated `NioChannelizer` and related classes.
+* Removed previously deprecated remote traversal side-effects and related infrastructure.
+* Removed previously deprecated `Serializers.DEFAULT_RESULT_SERIALIZER` and `Serializers.DEFAULT_REQUEST_SERIALIZER`.
+* Removed previously deprecated `decr` and `incr` from `Order`.
+* Removed previously deprecated `TraversalSource.withRemote()`.
+* Removed previously deprecated `ResponseHandlerContext` infrastructure.
+* Removed previously deprecated `VertexProgram` related infrastructure.
+* Removed previously deprecated SSL settings: `keyCertChainFile`, `keyFile`, `keyPassword` and `trustCertChainFile` and related infrastructure.
+* Removed previously deprecated `PropertyMapStep` constructor and `isIncludeTokens`.
+* Removed previously deprecated `StarGraph.builder()` and `StarGraph.Builder.create()`.
+* Removed previously deprecated `AbstractOpProcessor.generateMetaData(ChannelHandlerContext, RequestMessage, ResponseStatusCode, Iterator)`
+* Removed previously deprecated `BulkDumperVertexProgram` and `BulkLoaderVertexProgram`.
+
+==== Bugs
+
+* TINKERPOP-1619 TinkerGraphComputer worker count affects OptionalStep query results
+* TINKERPOP-2107 Spark fails to reattach properties
+* TINKERPOP-2157 SparkStarBarrierInterceptor injects (Byte) 0
+* TINKERPOP-2159 EventStrategy doesn't handle multi-valued properties
+* TINKERPOP-2175 Executor thread is not returned on channel close
+* TINKERPOP-2185 Use commons-configuration2 instead of commons-configuration *(breaking)*
+* TINKERPOP-2192 Gremlin.Net.Driver.Connection.Parse throws a NullReferenceException
+* TINKERPOP-2224 Detect and fix resource leak
+* TINKERPOP-2230 match() step unexpected behaviours
+* TINKERPOP-2232 RemoteStrategy does not call parent class TraversalStrategy __init__
+* TINKERPOP-2238 Fix remaining iterator leaks marked by @IgnoreIteratorLeak
+* TINKERPOP-2241 Client exception don't match Server exception when server  throw StackOverflowError
+* TINKERPOP-2248 Instability of driver for blocked requests
+* TINKERPOP-2257 transaction itty  may still be visited after commit
+* TINKERPOP-2264 Gremlin Python should deserialize g:Date to UTC
+* TINKERPOP-2266 Keep alive not started at connection creation
+* TINKERPOP-2274 Test of TinkerGraph Gremlin fail on Windows and non EN locale
+* TINKERPOP-2276 No constructor for remote connection in DSL generated traversal source
+* TINKERPOP-2283 GraphStep's ids null exception
+* TINKERPOP-2285 Error object is unreachable
+* TINKERPOP-2288 Get ConnectionPoolBusyException and then ServerUnavailableExceptions
+* TINKERPOP-2289 Use address instead of hostname for connection
+* TINKERPOP-2290 Javascript GLV connection refused error handling
+* TINKERPOP-2291 TraversalExplanation deserialization in GraphSON
+* TINKERPOP-2298 Bytecode.java  flattenArguments throw exception when null
+* TINKERPOP-2303 GremlinDsl generate addV instead of addE
+* TINKERPOP-2318 Edge properties dedup() not work with spark-gremlin *(breaking)*
+* TINKERPOP-2337 In upgrade guide for 3.4.2, the option RemoteConnection.PER_REQUEST_TIMEOUT does not exist
+* TINKERPOP-2338 drop() not removing all edge/meta properties
+* TINKERPOP-2341 GremlinClientExtensions.SubmitAsync hangs as it tries to dispose connection
+* TINKERPOP-2345 NullPointerException when Map key is not found for math()
+* TINKERPOP-2347 Remove invalid service descriptors from gremlin-shaded
+* TINKERPOP-2350 clone() is not deep copying Traversal internals
+* TINKERPOP-2351 Local Map ordering of keys can generate cast errors
+* TINKERPOP-2352 Gremlin Python driver default pool size makes Gremlin keep-alive difficult
+* TINKERPOP-2353 Error while Shutting Down Gremlin Server
+* TINKERPOP-2360 failed to deserializer int32 when gremlin-python submit bytecode with a big int value
+* TINKERPOP-2364 Injected ProfileStep should not be displayed in child traversals
+* TINKERPOP-2365 LazyBarrierStrategy adds a NoOpBarrierStep when profile() is present
+* TINKERPOP-2368 JAVA_OPTIONS are not properly expanded in gremlin-console
+* TINKERPOP-2369 Connections in ConnectionPool are not replaced in background when underlying channel is closed
+* TINKERPOP-2374 SaslAndHttpBasicAuthenticationHandler can't extract authorization
+* TINKERPOP-2383 has(T,Traversal) does not return results
+* TINKERPOP-2384 Inject and withSideEffect causing different outcomes in order step
+* TINKERPOP-2388 gremlinpython: Can't close DriverRemoteConnection
+* TINKERPOP-2403 Gremlin javascript Translator does not handle child traversals
+* TINKERPOP-2405 gremlinpython: traversal hangs when the connection is established but the servers stops responding later
+* TINKERPOP-2408 Iterator leak in HasContainer
+* TINKERPOP-2409 js: DriverRemoteConnection never times out if server uri not available.
+* TINKERPOP-2410 Free up server threads when client is closed
+* TINKERPOP-2425 Server closes HTTP connection for keepAlive as true
+* TINKERPOP-2432 Generate correct toString() representation of bytecode in Javascript
+* TINKERPOP-2433 typo in javadocs match() Type Parameters
+* TINKERPOP-2435 Gremlin Python sugar syntax for values() can lead to unexpected problems
+* TINKERPOP-2437 gremlin-driver hangs if ResultSet.statusAttributes().get() is called when the request throws
+* TINKERPOP-2439 P and TextP toString() is broken
+* TINKERPOP-2458 Bytecode Bindings lost when followed by a child traversal
+* TINKERPOP-2465 TestHelper.generateTempFileFromResource file handling is invalid on windows
+* TINKERPOP-2475 Barrier step touches one more element of next loop
+* TINKERPOP-2478 Console byte code translator has issues with "new Date()"
+* TINKERPOP-2496 GremlinDslProcessor fails when SocialTraversalSourceDsl overrides close
+* TINKERPOP-2505 Gremlin Python Client Query Times out at 30 seconds instead of the server timeout
+* TINKERPOP-2512 Duplicate jars in classpath when running gremlin-server.sh
+* TINKERPOP-2513 Generics insufficiently strict on property()
+* TINKERPOP-2514 Java client driver requests with same request ids hang
+* TINKERPOP-2516 Property folding has trouble with coalesce
+* TINKERPOP-2529 Global dedup() in reducing by() of group() detaches elements for OLTP
+* TINKERPOP-2531 Gremlin .NET driver ConnectionPool can remain without connections if server is down for 1-2 minutes
+
+==== Improvements
+
+* TINKERPOP-709 Consider Bounding Gremlin Pool Queue Size
+* TINKERPOP-1084 Branch option tokens should be allowed to be traversals.
+* TINKERPOP-1553 Deprecate store() in favor of aggregate(Scope)
+* TINKERPOP-1568 Change strategy application order *(breaking)*
+* TINKERPOP-1641 Kerberos authentication for gremlin-python
+* TINKERPOP-1682 by-modulator optimization strategy
+* TINKERPOP-1733 hasKey, hasValues should work on Element and Property
+* TINKERPOP-1810 Add Lambda.binaryOperator and Lambda.unaryOperator
+* TINKERPOP-1838 Python sample script
+* TINKERPOP-1886 Gremlin Python driver to periodically issue ping / heartbeat to gremlin server
+* TINKERPOP-1921 Support hasNext terminal step in GLVs
+* TINKERPOP-1994 LazyBarrierStrategy fully responsible for barrier() additions
+* TINKERPOP-2001 Support lambdas in Javascript
+* TINKERPOP-2014 Allow an ability to specify seeding for random methods such as coin, sample and Order.shuffle
+* TINKERPOP-2020 Support withComputer() for javascript
+* TINKERPOP-2046 Gremlin-Python: Support custom request headers in WebSocket request
+* TINKERPOP-2054 Support TraversalStrategy specification in gremlin-javascript
+* TINKERPOP-2076 Build with Java 11
+* TINKERPOP-2080 Remove deprecated TraversalSource.withRemote() *(breaking)*
+* TINKERPOP-2099 Property setting with null has different behavior between add and update *(breaking)*
+* TINKERPOP-2133 Use neo4j index lookup in Neo4jGraphStep with HasContainers containing TextP predicates
+* TINKERPOP-2168 GraphSON: P deserialization should be optimized
+* TINKERPOP-2213 Replace scriptEvaluationTimeout in favor of something more suitable to bytecode
+* TINKERPOP-2215 Better exception message for connection problems
+* TINKERPOP-2223 Update jackson databind to 2.9.9
+* TINKERPOP-2231 Remove deprecated bulk dumping/loading VertexPrograms *(breaking)*
+* TINKERPOP-2233 Remove deprecated Order decr/incr *(breaking)*
+* TINKERPOP-2235 Better handle the concept of null in traversals *(breaking)*
+* TINKERPOP-2236 Improve error messaging for TinkerGraph IdManagers that fail on conversions
+* TINKERPOP-2237 Prevent error when closing sessions that don't exist *(breaking)*
+* TINKERPOP-2239 Remove previously deprecated SSL configuration options *(breaking)*
+* TINKERPOP-2242 Bump to netty 4.1.36
+* TINKERPOP-2243 Add user-agent to RequestOptions
+* TINKERPOP-2245 Consolidate the executor for bytecode & string based client
+* TINKERPOP-2246 Consolidate the error propagation to the client
+* TINKERPOP-2250 Support toString serialization in GraphBinary
+* TINKERPOP-2251 Remove deprecated VertexProgram-related methods *(breaking)*
+* TINKERPOP-2252 A meaningful way to support session based byteCode interaction through gremlin-driver
+* TINKERPOP-2254 Rename AggregateStep and StoreStep given aggregate(Scope,String) *(breaking)*
+* TINKERPOP-2256 processAllStarts of AggregateStep should only be called when barrier is empty
+* TINKERPOP-2259 Default Java based driver and server operations to GraphBinary and remove Gryo *(breaking)*
+* TINKERPOP-2260 Update jackson databind 2.9.9.1
+* TINKERPOP-2262 Improve Netty protocol handling
+* TINKERPOP-2265 Deprecate Traversal.getSideEffects() functionality for remoting purposes
+* TINKERPOP-2269 Remove remote side-effect related infrastructure *(breaking)*
+* TINKERPOP-2270 Deprecate multi/metaproperty support in Neo4j
+* TINKERPOP-2271 Add console preference to control server-originated warning display
+* TINKERPOP-2272 Rename steps and tokens that conflict with standard python functions
+* TINKERPOP-2273 Remove deprecated ResponseHandlerContext infrastructure *(breaking)*
+* TINKERPOP-2277 Python sdk postpone the timing to create transport
+* TINKERPOP-2279 GraphBinary support in Python
+* TINKERPOP-2280 Prevent use of T values as property key overloads
+* TINKERPOP-2284 Make it easier to return more structure of graph elements
+* TINKERPOP-2295 Remove deprecated scriptEvaluationTimeout *(breaking)*
+* TINKERPOP-2296 Per query timeout not working from Python
+* TINKERPOP-2302 Add isOnGraphComputer() field accessor to ElementMapStep
+* TINKERPOP-2307 Add better error message for badly configured Channelizer
+* TINKERPOP-2310 Reduce Traversal.isRoot() to a check of EmptyStep *(breaking)*
+* TINKERPOP-2311 TraversalStrategies implementing Iterable *(breaking)*
+* TINKERPOP-2312 Empty keys to group() should group to null
+* TINKERPOP-2314 Employ by(String) for Map when possible and improve errors around incorrect types
+* TINKERPOP-2315 Implement some form of clone() or reset() for Traversal in GLVs
+* TINKERPOP-2317 Remove Python 2 support *(breaking)*
+* TINKERPOP-2320 [SECURITY] XMLInputFactory initialization in GraphMLReader introduces
+* TINKERPOP-2325 Generate traversals that will better yield index lookups with SPARQL
+* TINKERPOP-2327 Remove deprecated NIO protocol support *(breaking)*
+* TINKERPOP-2328 Do not close all connections if just one has became closed
+* TINKERPOP-2335 Drop support for older GLV runtimes
+* TINKERPOP-2336 Allow close of channel without having to wait for server
+* TINKERPOP-2349 Switch from Newtonsoft.Json to System.Text.Json *(breaking)*
+* TINKERPOP-2354 Document recommendation to reuse graph traversal source
+* TINKERPOP-2356 Bump to Jackson 2.10.x
+* TINKERPOP-2357 Add a command to clear the Gremlin Console screen
+* TINKERPOP-2361 Prevent using GraphTraversalSource spawned traversals as children *(breaking)*
+* TINKERPOP-2371 Add possibility to import constants with ImportGremlinPlugin
+* TINKERPOP-2376 Probability distribution controlled by weight when using sample step
+* TINKERPOP-2377 Investigate intermittent .NET GLV test failures
+* TINKERPOP-2389 Authorization support in TinkerPop
+* TINKERPOP-2391 Drop GLV Templating System
+* TINKERPOP-2392 Improve module level documentation for GLVs
+* TINKERPOP-2394 Unable to use __ class of a custom DSL when passing a script even if this class is imported *(breaking)*
+* TINKERPOP-2395 Gremlin Python doesn't support list as keys in groupCount
+* TINKERPOP-2396 TraverserSet should be extendable for GraphDB provider
+* TINKERPOP-2397 Don't create the default Gyro serializer if the caller specifies a different one
+* TINKERPOP-2401 Upgrade Jackson-databind to 2.11.x
+* TINKERPOP-2406 Delegate processing from event loop to worker threads
+* TINKERPOP-2407 Support deserialization of a dict that has a dict as a key
+* TINKERPOP-2412 Add missing query tests
+* TINKERPOP-2413 Prefer withEmbedded() to withGraph() on AnonymousTraversalSource
+* TINKERPOP-2415 Avoid unnecessary detached objects if not required
+* TINKERPOP-2416 MultiIterator should implement AutoCloseable
+* TINKERPOP-2418 Store authenticated user on server pipeline
+* TINKERPOP-2420 Support per query request options in .NET
+* TINKERPOP-2421 Support per query options in javascript
+* TINKERPOP-2426 Use Netty's WebSocketClientProtocolHandler
+* TINKERPOP-2427 Simplify Netty reference counting
+* TINKERPOP-2430 Looping Recipies
+* TINKERPOP-2431 Operating on Dropped Elements Recipes
+* TINKERPOP-2436 The gremlin server starts even if all graphs instantiation has failed
+* TINKERPOP-2438 Provide a way for scripts to respect with() specification of timeout
+* TINKERPOP-2440 Simplify driver by delegating keepAlive logic to Netty
+* TINKERPOP-2441 Add compression to WebSocket frames sent from client
+* TINKERPOP-2442 Make Translators that work in Java part of gremlin-core
+* TINKERPOP-2443 Improve testing of Translator instances for non-JVM languages with focus on Python as a model
+* TINKERPOP-2445 Speed up client initialization *(breaking)*
+* TINKERPOP-2446 Add Recipe for Optional Looping
+* TINKERPOP-2447 Improve handling of StackOverflowError for long traversals
+* TINKERPOP-2451 JavascriptTranslator for Java
+* TINKERPOP-2452 DotNetTranslator for Java
+* TINKERPOP-2453 Add WebSocket compression to gremlin-python
+* TINKERPOP-2455 Remove deprecated custom keep-alive functionality in the Java driver Channelizer *(breaking)*
+* TINKERPOP-2457 Add a max_content_length parameter to DriverRemoteConnection in the Python client
+* TINKERPOP-2460 Change groovy to provided scope in gremlin-driver *(breaking)*
+* TINKERPOP-2461 Align CoreImports with GroovyTranslator
+* TINKERPOP-2462 Duplicated BytecodeUtil and BytecodeHelper classes
+* TINKERPOP-2466 Improve syntax for Groovy scripts that use withStrategies()
+* TINKERPOP-2468 Stabilize shouldProcessSessionRequestsInOrder() test
+* TINKERPOP-2469 KrbException - Principal does not exist in test
+* TINKERPOP-2470 Bump gremlinpython to tornado 6.x
+* TINKERPOP-2472 GraphBinary support in .NET
+* TINKERPOP-2473 Prevent TraversalStrategy instances of the same type to be added to a TraversalSource
+* TINKERPOP-2474 withSack() Groovy translation output could be simplified
+* TINKERPOP-2476 Provide fully shaded version of Java driver
+* TINKERPOP-2479 Provide a way to set a custom GraphSONMapper for :bytecode command
+* TINKERPOP-2481 IdentityRemovalStrategy not installed *(breaking)*
+* TINKERPOP-2482 Rename wsConnectionTimeout to connectionSetupTimeout
+* TINKERPOP-2484 Python  IOLoop close errors
+* TINKERPOP-2485 Invalid http tests with ?gremlin=1-1
+* TINKERPOP-2494 Document Translator parameter extraction functionality
+* TINKERPOP-2499 PathRetractionStrategy returns inconsistent results when match() is not detected as the final step *(breaking)*
+* TINKERPOP-2500 Add none() step for all GLVs
+* TINKERPOP-2506 Expose client WebSocket connection status
+* TINKERPOP-2517 Introduce a retry status code to the server protocol
+* TINKERPOP-2527 Add a GroovyTranslator equivalent method to the Python client
+* TINKERPOP-2530 Transfer OyvindSabo/gremlint and OyvindSabo/gremlint.com to apache/tinkerpop/gremlint
+* TINKERPOP-2532 MaxBarrierSize of NoOpBarrierStep should be accessible
+* TINKERPOP-2533 Develop a grammar for Gremlin
+* TINKERPOP-2535 Netty 4.1.52 flagged as medium security violation
+* TINKERPOP-2537 Support bytecode based requests in sessions and remote tx()
+* TINKERPOP-2544 Modify site publishing scripts to include gremlint
+* TINKERPOP-2546 Change transport layer to use AIOHTTP instead of Tornado
+* TINKERPOP-2547 Provide an option to supply a callback before handshake submission
+* TINKERPOP-2550 Deadlock on Client initialization
+
 == TinkerPop 3.4.0 (Avant-Gremlin Construction #3 for Theremin and Flowers)
 
 image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/images/avant-gremlin.png[width=185]
@@ -133,7 +462,7 @@
 * Remove static initialization for `GraphSONMessageSerializerV1d0` and `GraphSONMessageSerializerV1d0` in Java driver.
 * Connections to the server in a connection pool are created in parallel instead of serially in Java Driver.
 * Connection pools for multiple endpoints are created in parallel instead of serially in Java Driver.
-* Introduced new HostNotAvailable exception to represent cases when no server with active connection is available. 
+* Introduced new HostNotAvailable exception to represent cases when no server with active connection is available.
 * Don't wait for new requests during shutdown of event loop group in Java Driver.
 
 ==== Bugs
@@ -991,6 +1320,8 @@
 * Bumped `httpclient` to 4.5.7.
 * Bumped `slf4j` to 1.7.25.
 * Bumped `commons-codec` to 1.12.
+* Bumped to Groovy 2.5.6.
+* Bumped to Hadoop 2.7.7.
 * Fixed partial response failures when using authentication in `gremlin-python`.
 * Fixed concurrency issues in `TraverserSet.toString()` and `ObjectWritable.toString()`.
 * Fixed a bug in `InlineFilterStrategy` that mixed up and's and or's when folding merging conditions together.
@@ -1930,7 +2261,7 @@
 * Fixed a bug in `RepeatUnrollStrategy` where `LoopsStep` and `LambdaHolder` should invalidate the strategy's application.
 * Deprecated `authentication.className` setting in favor of using `authentication.authenticator`.
 * Added `authentication.authenticationHandler` setting.
-* Added abstraction to authorization to allow users to plug in their own `AbstractAuthorizationHandler` implementations.
+* Added abstraction to authentication to allow users to plug in their own `AbstractAuthenticationHandler` implementations.
 * Fixed a `NullPointerException` bug in `B_LP_O_S_SE_SL_Traverser`.
 * `PathRetractionStrategy` now uses the marker-model to reduce recursive lookups of invalidating steps.
 * `ProfileStrategy` now uses the marker-model to reduce recursive lookups of `ProfileSideEffectStep`.
diff --git a/README.asciidoc b/README.asciidoc
index 4f8e659..3f2367d 100644
--- a/README.asciidoc
+++ b/README.asciidoc
@@ -29,7 +29,7 @@
 
 === Building and Testing
 
-TinkerPop uses link:https://maven.apache.org/[Maven] and requires `Java 1.8.0_40+` for proper building and proper operations. To build, execute unit tests and package Gremlin Console/Server run:
+TinkerPop uses link:https://maven.apache.org/[Maven] and requires `Java 11` for proper building and proper operations. To build, execute unit tests and package Gremlin Console/Server run:
 
 [source,bash]
 mvn clean install
diff --git a/bin/clean-branches.sh b/bin/clean-branches.sh
new file mode 100755
index 0000000..e347582
--- /dev/null
+++ b/bin/clean-branches.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+#
+#
+# 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.
+#
+
+for branch in $(git branch -r | grep -Po 'TINKERPOP[3]?-.*')
+do
+  jira=`sed 's/TINKERPOP3/TINKERPOP/' <<< $branch | grep -Po 'TINKERPOP-[0-9]*'`
+  curl -s https://issues.apache.org/jira/browse/$jira > /tmp/$jira
+  status=`cat /tmp/$jira | grep -A1 status-val | grep -Po '(?<=>)[^<]*(?=)' | head -n1`
+  title=`cat /tmp/$jira | grep -Po '(?<=<title>).*(?=</title>)' | head -n1 | recode html..ascii | sed 's/ - ASF JIRA//'`
+  if [ "$status" == "Closed" ]; then
+    if [ "$1" == "--delete" ]; then
+      git push origin --delete $branch
+      git branch -D $branch
+      git branch -r -D origin/$branch
+    else
+      echo "$branch -- $title"
+    fi
+  fi
+  rm /tmp/$jira
+done
diff --git a/bin/generate-home.sh b/bin/generate-home.sh
index d2077dd..643ac16 100755
--- a/bin/generate-home.sh
+++ b/bin/generate-home.sh
@@ -23,12 +23,21 @@
 rm -rf target/site/home
 mkdir -p target/site/
 
+pushd docs/gremlint
+
+npm install
+npm run build
+
+popd
+
 hash rsync 2> /dev/null
 
 if [ $? -eq 0 ]; then
   rsync -avq docs/site/home target/site --exclude template
+  rsync -avq docs/gremlint/build/ target/site/home/gremlint
 else
   cp -R docs/site/home target/site
+  cp -R docs/gremlint/build/. target/site/home/gremlint
   rm -rf target/site/home/template
 fi
 
diff --git a/bin/gephi-mock.py b/bin/gephi-mock.py
index 85501e6..1018677 100755
--- a/bin/gephi-mock.py
+++ b/bin/gephi-mock.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 #
 #
 # Licensed to the Apache Software Foundation (ASF) under one
@@ -19,7 +19,7 @@
 # under the License.
 #
 
-from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
+from http.server import BaseHTTPRequestHandler, HTTPServer
 
 
 class GephiHandler(BaseHTTPRequestHandler):
diff --git a/bin/validate-distribution.sh b/bin/validate-distribution.sh
index f3c386b..bfd06ce 100755
--- a/bin/validate-distribution.sh
+++ b/bin/validate-distribution.sh
@@ -140,6 +140,7 @@
 echo -n "* checking source files ... "
 find . -type f | xargs -n1 -I {} file {} --mime | grep 'charset=binary' | cut -f1 -d: |
   grep -Pv '^\./docs/(static|(site/home))/(img|images)/((icons|logos|policy|resources)/)?[^/]*\.(png|jpg|ico|pdf)$' |
+  grep -Pv '^\./docs/gremlint/(src|public)/[^/]*\.(png|jpg|ico)$' |
   grep -Pv '^./gremlin-dotnet/src/images/[^/]*\.(png|ico)$' |
   grep -Pv '^./gremlin-dotnet/.*\.snk$' |
   grep -Pv '^./gremlin-server/src/test/resources/[^/]*\.(p12|jks)$' |
diff --git a/docker/Dockerfile b/docker/Dockerfile
index 2d5398e..6fa1f9f 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -25,7 +25,7 @@
 RUN sh -c 'curl -s https://packages.microsoft.com/config/ubuntu/16.04/packages-microsoft-prod.deb -o packages-microsoft-prod.deb'
 RUN sh -c 'dpkg -i packages-microsoft-prod.deb'
 RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
-RUN apt-get install apt-transport-https ca-certificates
+RUN apt-get install apt-transport-https gnupg ca-certificates
 RUN sh -c 'echo "deb https://download.mono-project.com/repo/ubuntu stable-xenial main" | tee /etc/apt/sources.list.d/mono-official-stable.list'
 RUN apt-get update
 
@@ -37,7 +37,9 @@
 # python3 on xenial install 3.5.2 which is insufficient for newer versions of python/typing#259 so
 # custom build and install 3.6.9 and upgrade pip along the way. this could be resolved by using bionic
 # but trying to keep all of our release branches on the same docker image and the older versions suit 3.4.x+
-RUN apt-get install -y --force-yes python python-dev python-pip build-essential checkinstall zlib1g-dev libreadline-gplv2-dev libncursesw5-dev libssl-dev libsqlite3-dev tk-dev libgdbm-dev libc6-dev libbz2-dev
+ENV DEBIAN_FRONTEND=noninteractive
+RUN apt-get install -y python python-dev python-pip build-essential checkinstall zlib1g-dev libreadline-gplv2-dev \
+    libncursesw5-dev libssl-dev libsqlite3-dev tk-dev libgdbm-dev libc6-dev libbz2-dev libkrb5-dev krb5-user
 RUN cd /opt && wget https://www.python.org/ftp/python/3.6.9/Python-3.6.9.tgz && tar -xvf Python-3.6.9.tgz
 RUN cd /opt/Python-3.6.9 && ./configure && make && make install
 RUN ln -sf /usr/bin/python3.6.9 /usr/bin/python3
diff --git a/docker/gremlin-server.sh b/docker/gremlin-server.sh
index ee8d111..9d91da7 100755
--- a/docker/gremlin-server.sh
+++ b/docker/gremlin-server.sh
@@ -25,6 +25,7 @@
 
 DIR=`dirname $0`
 PROJECT_HOME=${DIR}/../
+ABS_PROJECT_HOME=$(dirname $(realpath $0))/..
 
 TIMESTAMP=$(date +%s)
 BUILD_TAG="gremlin-server-test-${TIMESTAMP}"
@@ -57,7 +58,8 @@
 sed -e "s/GREMLIN_SERVER_VERSION\$/${GREMLIN_SERVER_VERSION}/" docker/gremlin-server/Dockerfile.template > Dockerfile
 
 docker build -t tinkerpop:${BUILD_TAG} .
-docker run ${TINKERPOP_TEST_DOCKER_OPTS} ${REMOVE_CONTAINER} -ti -p 45940:45940 -p 45941:45941 -v "${HOME}"/.groovy:/root/.groovy -v "${HOME}"/.m2:/root/.m2 tinkerpop:${BUILD_TAG} ${@}
+docker run ${TINKERPOP_TEST_DOCKER_OPTS} ${REMOVE_CONTAINER} -p 45940:45940 -p 45941:45941 -p 45942:45942 -p 4588:4588 -h gremlin-server-test -v "${HOME}"/.groovy:/root/.groovy \
+    -v "${HOME}"/.m2:/root/.m2 -v ${ABS_PROJECT_HOME}/gremlin-test/target:/opt/gremlin-test -ti tinkerpop:${BUILD_TAG} ${@}
 
 status=$?
 popd > /dev/null
diff --git a/docker/gremlin-server/Dockerfile.template b/docker/gremlin-server/Dockerfile.template
index de4eb45..cbb0611 100644
--- a/docker/gremlin-server/Dockerfile.template
+++ b/docker/gremlin-server/Dockerfile.template
@@ -25,7 +25,7 @@
 RUN chmod 755 /opt/docker-entrypoint.sh
 ENV GREMLIN_SERVER_VERSION=GREMLIN_SERVER_VERSION
 
-EXPOSE 45940-45941
+EXPOSE 45940-45942 4588
 
 ENTRYPOINT ["/opt/docker-entrypoint.sh"]
 CMD []
diff --git a/docker/gremlin-server/docker-entrypoint.sh b/docker/gremlin-server/docker-entrypoint.sh
index ae75116..7031cec 100644
--- a/docker/gremlin-server/docker-entrypoint.sh
+++ b/docker/gremlin-server/docker-entrypoint.sh
@@ -19,18 +19,71 @@
 #
 
 TINKERPOP_HOME=/opt/gremlin-server
-
 cp /opt/test/scripts/* ${TINKERPOP_HOME}/scripts
 
 IP=$(hostname -i)
-echo "#######################"
+
+echo "#############################################################################"
 echo IP is $IP
-echo "#######################"
+echo
+echo Available Gremlin Server instances:
+echo "ws://${IP}:45940/gremlin with anonymous access"
+echo "ws://${IP}:45941/gremlin with basic authentication (stephen/password)"
+echo "ws://${IP}:45942/gremlin with kerberos authentication (stephen/password)"
+echo
+echo "See docker/gremlin-server/docker-entrypoints.sh for transcripts per GLV."
+echo "#############################################################################"
 
 cp *.yaml ${TINKERPOP_HOME}/conf/
 
 java -version
 
-/opt/gremlin-server/bin/gremlin-server.sh install org.apache.tinkerpop gremlin-python ${GREMLIN_SERVER_VERSION}
 /opt/gremlin-server/bin/gremlin-server.sh conf/gremlin-server-integration.yaml &
-exec /opt/gremlin-server/bin/gremlin-server.sh conf/gremlin-server-integration-secure.yaml
+
+/opt/gremlin-server/bin/gremlin-server.sh conf/gremlin-server-integration-secure.yaml &
+
+java -cp /opt/gremlin-test/gremlin-test-${GREMLIN_SERVER_VERSION}-jar-with-dependencies.jar \
+     -Dlog4j.configuration="file:/opt/gremlin-server/conf/log4j-server.properties" \
+     org.apache.tinkerpop.gremlin.server.KdcFixture /opt/gremlin-server &
+
+export JAVA_OPTIONS="-Xms512m -Xmx4096m -Djava.security.krb5.conf=/opt/gremlin-server/target/kdc/krb5.conf"
+exec /opt/gremlin-server/bin/gremlin-server.sh conf/gremlin-server-integration-krb5.yaml
+
+
+#######################################################################
+# Transcripts for connecting to gremlin-server-test using various GLV's
+#######################################################################
+#
+# cd ${APACHE_TINKERPOP}                              # first terminal: location of cloned gitrepo
+# docker/gremlin-server.sh
+
+# cd ${APACHE_TINKERPOP}                              # second terminal
+# export KRB5_CONFIG=`pwd`/docker/gremlin-server/krb5.conf
+# echo 'password' | kinit stephen
+# klist
+
+# Gremlin-Groovy
+# --------------
+# KRB5_OPTION="-Djava.security.krb5.conf=`pwd`/docker/gremlin-server/krb5.conf"
+# JAAS_OPTION="-Djava.security.auth.login.config=`pwd`/docker/gremlin-server/gremlin-console-jaas.conf"
+# export JAVA_OPTIONS="${KRB5_OPTION} ${JAAS_OPTION}"
+# cd gremlin-console/target/apache-tinkerpop-gremlin-console-3.x.y-SNAPSHOT-standalone
+# If necessary (versions 3.4.2-3.4.6): in bin/gremlin.sh replace JVM_OPTS+=( "${JAVA_OPTIONS}" ) by JVM_OPTS+=( ${JAVA_OPTIONS} )
+# bin/gremlin.sh
+# gremlin> cluster = Cluster.build("172.17.0.2").port(45940).create()
+# gremlin> cluster = Cluster.build("172.17.0.2").port(45941).credentials("stephen", "password").create()
+# gremlin> cluster = Cluster.build("172.17.0.2").port(45942).addContactPoint("gremlin-server-test").protocol("test-service").jaasEntry("GremlinConsole").create()
+# gremlin> g = traversal().withRemote(DriverRemoteConnection.using(cluster, "gmodern"))
+# gremlin> g.V()
+
+# Gremlin-Python
+# --------------
+# cd gremlin-python/target/python3
+# source env/bin/activate
+# python
+# >>> from gremlin_python.process.anonymous_traversal import traversal
+# >>> from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection
+# >>> g = traversal().withRemote(DriverRemoteConnection('ws://172.17.0.2:45940/gremlin','gmodern'))
+# >>> g = traversal().withRemote(DriverRemoteConnection('ws://172.17.0.2:45941/gremlin','gmodern', username='stephen', password='password'))
+# >>> g = traversal().withRemote(DriverRemoteConnection('ws://172.17.0.2:45942/gremlin','gmodern', kerberized_service='test-service@gremlin-server-test'))
+# >>> g.V().toList()
diff --git a/docker/gremlin-server/gremlin-console-jaas.conf b/docker/gremlin-server/gremlin-console-jaas.conf
new file mode 100644
index 0000000..13b92bb
--- /dev/null
+++ b/docker/gremlin-server/gremlin-console-jaas.conf
@@ -0,0 +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
+ *
+ * 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.
+ */
+
+GremlinConsole {
+  com.sun.security.auth.module.Krb5LoginModule required
+  doNotPrompt=true
+  useTicketCache=true;
+};
diff --git a/docker/gremlin-server/gremlin-server-integration-krb5.yaml b/docker/gremlin-server/gremlin-server-integration-krb5.yaml
new file mode 100644
index 0000000..cb7e737
--- /dev/null
+++ b/docker/gremlin-server/gremlin-server-integration-krb5.yaml
@@ -0,0 +1,67 @@
+# 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.
+
+host: 0.0.0.0
+port: 45942
+evaluationTimeout: 30000
+graphs: {
+  graph: conf/tinkergraph-empty.properties,
+  classic: conf/tinkergraph-empty.properties,
+  modern: conf/tinkergraph-empty.properties,
+  crew: conf/tinkergraph-empty.properties,
+  grateful: conf/tinkergraph-empty.properties,
+  sink: conf/tinkergraph-empty.properties}
+scriptEngines: {
+  gremlin-groovy: {
+    plugins: { org.apache.tinkerpop.gremlin.server.jsr223.GremlinServerGremlinPlugin: {},
+               org.apache.tinkerpop.gremlin.tinkergraph.jsr223.TinkerGraphGremlinPlugin: {},
+               org.apache.tinkerpop.gremlin.groovy.jsr223.GroovyCompilerGremlinPlugin: {expectedCompilationTime: 30000},
+               org.apache.tinkerpop.gremlin.jsr223.ImportGremlinPlugin: {classImports: [java.lang.Math], methodImports: [java.lang.Math#*]},
+               org.apache.tinkerpop.gremlin.jsr223.ScriptFileGremlinPlugin: {files: [scripts/generate-all.groovy]}}}}
+serializers:
+  - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV1d0], custom: [groovy.json.JsonBuilder;org.apache.tinkerpop.gremlin.driver.ser.JsonBuilderGryoSerializer]}}
+  - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3d0], custom: [groovy.json.JsonBuilder;org.apache.tinkerpop.gremlin.driver.ser.JsonBuilderGryoSerializer]}}
+  - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoLiteMessageSerializerV1d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV1d0], custom: [groovy.json.JsonBuilder;org.apache.tinkerpop.gremlin.driver.ser.JsonBuilderGryoSerializer]}}
+  - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0, config: { serializeResultToString: true}}
+  - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0, config: { serializeResultToString: true}}
+  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV3d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3d0] }}
+  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV2d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV2d0] }}
+  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV1d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV1d0] }}
+  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1 }
+  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1, config: { serializeResultToString: true }}
+processors:
+  - { className: org.apache.tinkerpop.gremlin.server.op.session.SessionOpProcessor, config: { sessionTimeout: 28800000 }}
+  - { className: org.apache.tinkerpop.gremlin.server.op.standard.StandardOpProcessor, config: {}}
+metrics: {
+  slf4jReporter: {enabled: true, interval: 180000}}
+gremlinPool: 8
+strictTransactionManagement: false
+idleConnectionTimeout: 0
+keepAliveInterval: 0
+maxInitialLineLength: 4096
+maxHeaderSize: 8192
+maxChunkSize: 8192
+maxContentLength: 1000000
+maxAccumulationBufferComponents: 1024
+resultIterationBatchSize: 64
+writeBufferLowWaterMark: 32768
+writeBufferHighWaterMark: 65536
+authentication: {
+  authenticator: org.apache.tinkerpop.gremlin.server.auth.Krb5Authenticator,
+  config: {
+    principal: test-service/gremlin-server-test@TEST.COM,
+    keytab: /opt/gremlin-server/target/kdc/test-service.keytab}}
diff --git a/docker/gremlin-server/gremlin-server-integration-secure.yaml b/docker/gremlin-server/gremlin-server-integration-secure.yaml
index c489e07..e6a999f 100644
--- a/docker/gremlin-server/gremlin-server-integration-secure.yaml
+++ b/docker/gremlin-server/gremlin-server-integration-secure.yaml
@@ -17,7 +17,7 @@
 
 host: 0.0.0.0
 port: 45941
-scriptEvaluationTimeout: 30000
+evaluationTimeout: 30000
 graphs: {
   graph: conf/tinkergraph-empty.properties,
   classic: conf/tinkergraph-empty.properties,
@@ -31,10 +31,7 @@
                org.apache.tinkerpop.gremlin.tinkergraph.jsr223.TinkerGraphGremlinPlugin: {},
                org.apache.tinkerpop.gremlin.groovy.jsr223.GroovyCompilerGremlinPlugin: {expectedCompilationTime: 30000},
                org.apache.tinkerpop.gremlin.jsr223.ImportGremlinPlugin: {classImports: [java.lang.Math], methodImports: [java.lang.Math#*]},
-               org.apache.tinkerpop.gremlin.jsr223.ScriptFileGremlinPlugin: {files: [scripts/generate-all.groovy]}}},
-  gremlin-jython: {},
-  gremlin-python: {}
-}
+               org.apache.tinkerpop.gremlin.jsr223.ScriptFileGremlinPlugin: {files: [scripts/generate-all.groovy]}}}}
 serializers:
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV1d0], custom: [groovy.json.JsonBuilder;org.apache.tinkerpop.gremlin.driver.ser.JsonBuilderGryoSerializer]}}
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3d0], custom: [groovy.json.JsonBuilder;org.apache.tinkerpop.gremlin.driver.ser.JsonBuilderGryoSerializer]}}
@@ -51,6 +48,7 @@
   - { className: org.apache.tinkerpop.gremlin.server.op.standard.StandardOpProcessor, config: {}}
 metrics: {
   slf4jReporter: {enabled: true, interval: 180000}}
+gremlinPool: 8
 strictTransactionManagement: false
 idleConnectionTimeout: 0
 keepAliveInterval: 0
diff --git a/docker/gremlin-server/gremlin-server-integration.yaml b/docker/gremlin-server/gremlin-server-integration.yaml
index 7c5445a..7f56673 100644
--- a/docker/gremlin-server/gremlin-server-integration.yaml
+++ b/docker/gremlin-server/gremlin-server-integration.yaml
@@ -17,7 +17,7 @@
 
 host: 0.0.0.0
 port: 45940
-scriptEvaluationTimeout: 30000
+evaluationTimeout: 30000
 graphs: {
   graph: conf/tinkergraph-empty.properties,
   classic: conf/tinkergraph-empty.properties,
@@ -31,10 +31,7 @@
                org.apache.tinkerpop.gremlin.tinkergraph.jsr223.TinkerGraphGremlinPlugin: {},
                org.apache.tinkerpop.gremlin.groovy.jsr223.GroovyCompilerGremlinPlugin: {expectedCompilationTime: 30000},
                org.apache.tinkerpop.gremlin.jsr223.ImportGremlinPlugin: {classImports: [java.lang.Math], methodImports: [java.lang.Math#*]},
-               org.apache.tinkerpop.gremlin.jsr223.ScriptFileGremlinPlugin: {files: [scripts/generate-all.groovy]}}},
-  gremlin-jython: {},
-  gremlin-python: {}
-}
+               org.apache.tinkerpop.gremlin.jsr223.ScriptFileGremlinPlugin: {files: [scripts/generate-all.groovy]}}}}
 serializers:
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV1d0], custom: [groovy.json.JsonBuilder;org.apache.tinkerpop.gremlin.driver.ser.JsonBuilderGryoSerializer]}}
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3d0], custom: [groovy.json.JsonBuilder;org.apache.tinkerpop.gremlin.driver.ser.JsonBuilderGryoSerializer]}}
@@ -51,6 +48,7 @@
   - { className: org.apache.tinkerpop.gremlin.server.op.standard.StandardOpProcessor, config: {}}
 metrics: {
   slf4jReporter: {enabled: true, interval: 180000}}
+gremlinPool: 8
 strictTransactionManagement: false
 idleConnectionTimeout: 0
 keepAliveInterval: 0
diff --git a/docker/gremlin-server/krb5.conf b/docker/gremlin-server/krb5.conf
new file mode 100644
index 0000000..3f9c322
--- /dev/null
+++ b/docker/gremlin-server/krb5.conf
@@ -0,0 +1,29 @@
+#
+# 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.
+#
+
+[libdefaults]
+    kdc_realm = TEST.COM
+    default_realm = TEST.COM
+    udp_preference_limit = 4096
+    kdc_tcp_port = 4588
+    kdc_udp_port = 4588
+
+[realms]
+    TEST.COM = {
+        kdc = 172.17.0.2:4588
+    }
diff --git a/docker/scripts/build.sh b/docker/scripts/build.sh
index fb7d16e..d616aba 100755
--- a/docker/scripts/build.sh
+++ b/docker/scripts/build.sh
@@ -76,7 +76,7 @@
   cp settings.xml ~/.m2/
 fi
 
-export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
+export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
 mvn clean install process-resources --batch-mode ${TINKERPOP_BUILD_OPTIONS} || exit 1
 [ -z "${BUILD_JAVA_DOCS}" ] || mvn process-resources -Djavadoc || exit 1
 
diff --git a/docs/gremlint/.gitignore b/docs/gremlint/.gitignore
new file mode 100644
index 0000000..53e027a
--- /dev/null
+++ b/docs/gremlint/.gitignore
@@ -0,0 +1,19 @@
+# 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.
+
+node_modules
+build
\ No newline at end of file
diff --git a/docs/gremlint/.prettierrc b/docs/gremlint/.prettierrc
new file mode 100644
index 0000000..a0d1c9a
--- /dev/null
+++ b/docs/gremlint/.prettierrc
@@ -0,0 +1,5 @@
+{
+  "printWidth": 120,
+  "trailingComma": "all",
+  "singleQuote": true
+}
diff --git a/gremlin-python/src/main/jython/LICENSE b/docs/gremlint/LICENSE
similarity index 100%
copy from gremlin-python/src/main/jython/LICENSE
copy to docs/gremlint/LICENSE
diff --git a/docs/gremlint/README.md b/docs/gremlint/README.md
new file mode 100644
index 0000000..382d919
--- /dev/null
+++ b/docs/gremlint/README.md
@@ -0,0 +1,69 @@
+<!--
+  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.
+-->
+
+![Gremlint Github Header 1920x1024](https://user-images.githubusercontent.com/25663729/88488788-d5a73700-cf8f-11ea-9adb-03d62c77c1b7.png)
+
+### What is [gremlint.com](https://gremlint.com)?
+
+[Gremlint](https://github.com/apache/tinkerpop/tree/master/gremlint) is a code formatting library which parses Gremlin queries and rewrites them to adhere to certain styling rules.
+
+[Gremlint.com](https://gremlint.com) is a website which utilizes the Gremlint library to give users an online "living" style guide for Gremlin queries. It also serves as a platform for showcasing the features of Gremlint.
+
+### Give it a try!
+
+https://gremlint.com
+
+## Available Scripts
+
+In the project directory, you can run:
+
+```
+npm install
+```
+
+Installs dependencies.
+
+```
+npm start
+```
+
+Runs the app in the development mode.\
+Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
+
+The page will reload if you make edits.\
+You will also see any lint errors in the console.
+
+```
+npm test
+```
+
+Launches the test runner in the interactive watch mode.\
+See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
+
+```
+npm run build
+```
+
+Builds the app for production to the `build` folder.\
+It correctly bundles React in production mode and optimizes the build for the best performance.
+
+The build is minified and the filenames include the hashes.\
+Your app is ready to be deployed!
+
+See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
diff --git a/docs/gremlint/package.json b/docs/gremlint/package.json
new file mode 100644
index 0000000..be3b307
--- /dev/null
+++ b/docs/gremlint/package.json
@@ -0,0 +1,58 @@
+{
+  "homepage": "/gremlint",
+  "name": "gremlint.com",
+  "version": "0.1.0",
+  "private": true,
+  "dependencies": {
+    "@testing-library/jest-dom": "^5.11.4",
+    "@testing-library/react": "^11.1.0",
+    "@testing-library/user-event": "^12.1.10",
+    "@types/jest": "^26.0.15",
+    "@types/node": "^12.0.0",
+    "@types/react": "^16.9.53",
+    "@types/react-dom": "^16.9.8",
+    "gremlint": "github:OyvindSabo/gremlint#master",
+    "react": "^17.0.1",
+    "react-dom": "^17.0.1",
+    "react-scripts": "^4.0.3",
+    "sharp-router": "^4.1.5",
+    "styled-components": "^5.2.1",
+    "typescript": "^4.0.3",
+    "web-vitals": "^0.2.4"
+  },
+  "scripts": {
+    "predeploy": "npm run build",
+    "deploy": "gh-pages -d build",
+    "start": "react-scripts start",
+    "build": "react-scripts build",
+    "test": "react-scripts test",
+    "eject": "react-scripts eject"
+  },
+  "author": "Øyvind Sæbø",
+  "license": "Apache-2.0",
+  "eslintConfig": {
+    "extends": [
+      "react-app",
+      "react-app/jest"
+    ]
+  },
+  "browserslist": {
+    "production": [
+      ">0.2%",
+      "not dead",
+      "not op_mini all"
+    ],
+    "development": [
+      "last 1 chrome version",
+      "last 1 firefox version",
+      "last 1 safari version"
+    ]
+  },
+  "devDependencies": {
+    "@types/styled-components": "^5.1.4",
+    "gh-pages": "^3.1.0",
+    "prettier": "^2.1.2",
+    "tslint": "^6.1.3",
+    "tslint-config-prettier": "^1.18.0"
+  }
+}
diff --git a/docs/gremlint/public/CNAME b/docs/gremlint/public/CNAME
new file mode 100644
index 0000000..755baaf
--- /dev/null
+++ b/docs/gremlint/public/CNAME
@@ -0,0 +1 @@
+gremlint.com
\ No newline at end of file
diff --git a/docs/gremlint/public/favicon.ico b/docs/gremlint/public/favicon.ico
new file mode 100644
index 0000000..1c73e71
--- /dev/null
+++ b/docs/gremlint/public/favicon.ico
Binary files differ
diff --git a/docs/gremlint/public/index.html b/docs/gremlint/public/index.html
new file mode 100644
index 0000000..a386e50
--- /dev/null
+++ b/docs/gremlint/public/index.html
@@ -0,0 +1,60 @@
+<!--
+  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.
+-->
+
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8" />
+    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
+    <meta name="viewport" content="width=device-width, initial-scale=1" />
+    <meta name="theme-color" content="#000000" />
+    <meta name="description" content="Web site created using create-react-app" />
+    <meta name="google-site-verification" content="8rkkiQkZaBwVUAUBxSY6Nj_EBHqCGPEYnEJmlyXuLnw" />
+    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
+    <!--
+      manifest.json provides metadata used when your web app is installed on a
+      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
+    -->
+    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
+    <!--
+      Notice the use of %PUBLIC_URL% in the tags above.
+      It will be replaced with the URL of the `public` folder during the build.
+      Only files inside the `public` folder can be referenced from the HTML.
+
+      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
+      work correctly both with client-side routing and a non-root public URL.
+      Learn how to configure a non-root public URL by running `npm run build`.
+    -->
+    <title>React App</title>
+  </head>
+  <body>
+    <noscript>You need to enable JavaScript to run this app.</noscript>
+    <div id="root"></div>
+    <!--
+      This HTML file is a template.
+      If you open it directly in the browser, you will see an empty page.
+
+      You can add webfonts, meta tags, or analytics to this file.
+      The build step will place the bundled scripts into the <body> tag.
+
+      To begin the development, run `npm start` or `yarn start`.
+      To create a production bundle, use `npm run build` or `yarn build`.
+    -->
+  </body>
+</html>
diff --git a/docs/gremlint/public/manifest.json b/docs/gremlint/public/manifest.json
new file mode 100644
index 0000000..3292390
--- /dev/null
+++ b/docs/gremlint/public/manifest.json
@@ -0,0 +1,15 @@
+{
+  "short_name": "Gremlint",
+  "name": "Gremlint - Gremlin query formatter",
+  "icons": [
+    {
+      "src": "favicon.ico",
+      "sizes": "512x512",
+      "type": "image/png"
+    }
+  ],
+  "start_url": ".",
+  "display": "standalone",
+  "theme_color": "#000000",
+  "background_color": "#ffffff"
+}
diff --git a/docs/gremlint/public/robots.txt b/docs/gremlint/public/robots.txt
new file mode 100644
index 0000000..3c2d5a1
--- /dev/null
+++ b/docs/gremlint/public/robots.txt
@@ -0,0 +1,20 @@
+# 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.
+
+# https://www.robotstxt.org/robotstxt.html
+User-agent: *
+Disallow:
diff --git a/docs/gremlint/src/App.css b/docs/gremlint/src/App.css
new file mode 100644
index 0000000..65a176b
--- /dev/null
+++ b/docs/gremlint/src/App.css
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+.App {
+  text-align: center;
+}
+
+.App-logo {
+  height: 40vmin;
+  pointer-events: none;
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  .App-logo {
+    animation: App-logo-spin infinite 20s linear;
+  }
+}
+
+.App-header {
+  background-color: #282c34;
+  min-height: 100vh;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  font-size: calc(10px + 2vmin);
+  color: white;
+}
+
+.App-link {
+  color: #61dafb;
+}
+
+@keyframes App-logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
diff --git a/docs/gremlint/src/App.test.tsx b/docs/gremlint/src/App.test.tsx
new file mode 100644
index 0000000..7c03a33
--- /dev/null
+++ b/docs/gremlint/src/App.test.tsx
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+import App from './App';
+
+test('renders learn react link', () => {
+  render(<App />);
+  const linkElement = screen.getByText(/learn react/i);
+  expect(linkElement).toBeInTheDocument();
+});
diff --git a/docs/gremlint/src/App.tsx b/docs/gremlint/src/App.tsx
new file mode 100644
index 0000000..d1bd9ef
--- /dev/null
+++ b/docs/gremlint/src/App.tsx
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+import React, { useState } from 'react';
+import './App.css';
+import styled from 'styled-components';
+import { useRouter } from 'sharp-router';
+import router from './router';
+import FadeIn from './components/FadeIn';
+import Navigator from './components/Navigator';
+import QueryFormatter from './views/QueryFormatter';
+import StyleGuide from './views/StyleGuide';
+import LoadingAnimation from './components/LoadingAnimation';
+
+const ViewWrapper = styled.div`
+  width: min(800px, 100vw);
+  margin-left: calc(50vw - min(400px, 50vw));
+`;
+
+const App = () => {
+  const { matchedRoute } = useRouter(router);
+  const [loadingComplete, setLoadingComplete] = useState(false);
+  if (!loadingComplete) return <LoadingAnimation onLoadingComplete={() => setLoadingComplete(true)} />;
+  return (
+    <FadeIn>
+      <div>
+        <Navigator matchedRoute={matchedRoute} />
+        <div>
+          <ViewWrapper>
+            {matchedRoute === '/' ? <QueryFormatter /> : matchedRoute === '/style-guide' ? <StyleGuide /> : null}
+          </ViewWrapper>
+        </div>
+      </div>
+    </FadeIn>
+  );
+};
+
+export default App;
diff --git a/docs/gremlint/src/components/CodePreview.tsx b/docs/gremlint/src/components/CodePreview.tsx
new file mode 100644
index 0000000..1179dea
--- /dev/null
+++ b/docs/gremlint/src/components/CodePreview.tsx
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+import React from 'react';
+import styled from 'styled-components';
+import { HTMLAttributes } from 'react';
+import { disabledTextColor, textColor } from '../styleVariables';
+
+const CodePreviewWrapper = styled.div`
+  padding: 10px;
+`;
+
+const CodePreviewBox = styled.div`
+  border-radius: 5px;
+  font-family: 'Courier New', Courier, monospace;
+  background: rgba(0, 0, 0, 0.05);
+  outline: none;
+  font-size: 15px;
+  padding: 10px;
+  border: none;
+  resize: none;
+  box-shadow: inset rgba(0, 0, 0, 0.5) 0 0 10px -5px;
+  white-space: pre-wrap;
+  overflow: auto;
+  position: relative;
+`;
+
+const Code = styled.div`
+  color: ${textColor};
+  line-height: 20px;
+  font-size: 15px;
+`;
+
+const CodeRuler = styled.div<{ $maxLineLength: number }>`
+  top: 0;
+  left: 0;
+  width: calc(10px + ${({ $maxLineLength }) => $maxLineLength}ch);
+  border-right: 1px solid ${disabledTextColor};
+  position: absolute;
+  height: 100%;
+  pointer-events: none;
+`;
+
+type CodePreviewProps = {
+  maxLineLength?: number;
+} & HTMLAttributes<HTMLSpanElement>;
+
+const CodePreview = ({ maxLineLength, children }: CodePreviewProps) => (
+  <CodePreviewWrapper>
+    <CodePreviewBox>
+      <Code>{children}</Code>
+      {maxLineLength ? <CodeRuler $maxLineLength={maxLineLength} /> : null}
+    </CodePreviewBox>
+  </CodePreviewWrapper>
+);
+
+export default CodePreview;
diff --git a/docs/gremlint/src/components/FadeIn.tsx b/docs/gremlint/src/components/FadeIn.tsx
new file mode 100644
index 0000000..621fb74
--- /dev/null
+++ b/docs/gremlint/src/components/FadeIn.tsx
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+import React, { HTMLAttributes, useEffect, useState } from 'react';
+import styled from 'styled-components';
+
+const FadeInWrapper = styled.div<{ $opacity: number }>`
+  opacity: ${({ $opacity }) => $opacity};
+`;
+
+const FadeIn = ({ children, ...props }: HTMLAttributes<HTMLDivElement>) => {
+  const [opacity, setOpacity] = useState(0);
+
+  useEffect(() => {
+    setTimeout(() => setOpacity(1));
+  }, []);
+
+  return (
+    <FadeInWrapper $opacity={opacity} {...props}>
+      {children}
+    </FadeInWrapper>
+  );
+};
+
+export default FadeIn;
diff --git a/docs/gremlint/src/components/LoadingAnimation.tsx b/docs/gremlint/src/components/LoadingAnimation.tsx
new file mode 100644
index 0000000..0fa89a6
--- /dev/null
+++ b/docs/gremlint/src/components/LoadingAnimation.tsx
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+
+import React, { useEffect, useState } from 'react';
+import styled from 'styled-components';
+import { white } from '../styleVariables';
+import gremlintLoadingLogoColored from '../gremlint-loading-logo-colored.png';
+import gremlintLoadingLogoGrayscale from '../gremlint-loading-logo-grayscale.png';
+
+const LoadingAnimationWrapper = styled.div`
+  position: fixed;
+  background: ${white};
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  z-index: 2;
+`;
+
+const GrayscaleImageWrapper = styled.div`
+  height: 100%;
+  width: 100%;
+  position: absolute;
+  bottom: calc(50vh - 25vmin);
+`;
+
+const ColoredImageWrapper = styled.div<{ $loadingCompletion: number }>`
+  overflow: hidden;
+  height: ${({ $loadingCompletion }) => $loadingCompletion / 2}vmin;
+  width: 100%;
+  position: absolute;
+  bottom: calc(50vh - 25vmin);
+`;
+
+const Image = styled.img<{ $opacity: number }>`
+  opacity: ${({ $opacity }) => $opacity};
+  transition: 0.25s;
+  height: 50vmin;
+  width: 50vmin;
+  display: block;
+  margin: auto;
+  position: absolute;
+  bottom: 0;
+  left: 50%;
+  transform: translate(-50%, 0);
+`;
+
+type LoadingAnimationProps = {
+  onLoadingComplete: VoidFunction;
+};
+
+const LoadingAnimation = ({ onLoadingComplete }: LoadingAnimationProps) => {
+  const [loadingCompletion, setLoadingCompletion] = useState(0);
+  const [coloredImageHasLoaded, setColoredImageHasLoaded] = useState(false);
+  const [grayscaleImageHasLoaded, setGrayscaleImageHasLoaded] = useState(false);
+
+  useEffect(() => {
+    setTimeout(
+      () => {
+        if (loadingCompletion < 100) {
+          if (coloredImageHasLoaded && grayscaleImageHasLoaded) {
+            setLoadingCompletion(loadingCompletion + 1);
+          }
+        } else {
+          setTimeout(onLoadingComplete, 250);
+        }
+      },
+      loadingCompletion === 0 ? 250 : 10,
+    );
+  }, [loadingCompletion, coloredImageHasLoaded, grayscaleImageHasLoaded, onLoadingComplete]);
+
+  return (
+    <LoadingAnimationWrapper>
+      <GrayscaleImageWrapper>
+        <Image
+          src={gremlintLoadingLogoGrayscale}
+          $opacity={grayscaleImageHasLoaded && loadingCompletion !== 100 ? 1 : 0}
+          onLoad={() => setGrayscaleImageHasLoaded(true)}
+        />
+      </GrayscaleImageWrapper>
+      <ColoredImageWrapper $loadingCompletion={loadingCompletion}>
+        <Image
+          src={gremlintLoadingLogoColored}
+          $opacity={loadingCompletion !== 100 ? 1 : 0}
+          onLoad={() => setColoredImageHasLoaded(true)}
+        />
+      </ColoredImageWrapper>
+    </LoadingAnimationWrapper>
+  );
+};
+
+export default LoadingAnimation;
diff --git a/docs/gremlint/src/components/NavigationButton.tsx b/docs/gremlint/src/components/NavigationButton.tsx
new file mode 100644
index 0000000..55aebbe
--- /dev/null
+++ b/docs/gremlint/src/components/NavigationButton.tsx
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+import React from 'react';
+import styled from 'styled-components';
+import { highlightColor, highlightedTextColor, textColor } from '../styleVariables';
+
+const NavigationButtonWrapper = styled.span`
+  display: inline-block;
+  vertical-align: bottom;
+  padding: 10px;
+  box-sizing: border-box;
+  height: 40px;
+  width: 160px;
+`;
+
+const NavigationButtonLink = styled.a<{ $isSelected: boolean }>`
+  text-decoration: none;
+  display: inline-block;
+  height: 20px;
+  line-height: 20px;
+  font-size: 15px;
+  color: ${({ $isSelected }) => ($isSelected ? highlightedTextColor : textColor)};
+  border-bottom: ${({ $isSelected }) => ($isSelected ? `2px solid ${highlightColor}` : 'none')};
+  &:hover {
+    color: ${highlightedTextColor};
+  }
+`;
+
+type NavigationButtonProps = {
+  isSelected: boolean;
+  href: string;
+  label: string;
+};
+
+const NavigationButton = ({ isSelected, href, label }: NavigationButtonProps) => (
+  <NavigationButtonWrapper>
+    <NavigationButtonLink href={href} $isSelected={isSelected}>
+      {label}
+    </NavigationButtonLink>
+  </NavigationButtonWrapper>
+);
+
+export default NavigationButton;
diff --git a/docs/gremlint/src/components/Navigator.tsx b/docs/gremlint/src/components/Navigator.tsx
new file mode 100644
index 0000000..fe62af5
--- /dev/null
+++ b/docs/gremlint/src/components/Navigator.tsx
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+import React from 'react';
+import styled from 'styled-components';
+import NavigationButton from './NavigationButton';
+import { white } from '../styleVariables';
+
+const NavigatorWrapper = styled.div`
+  background: ${white};
+  box-shadow: ${white} 0 0 10px;
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  z-index: 1;
+`;
+
+const NavigatorCenterContainer = styled.div`
+  width: min(800px, 100vw);
+  margin-left: calc(50vw - min(400px, 50vw));
+`;
+
+const Spacer = styled.div`
+  height: 40px;
+`;
+
+type NavigatorProps = {
+  matchedRoute: string;
+};
+
+const Navigator = ({ matchedRoute }: NavigatorProps) => (
+  <div>
+    <NavigatorWrapper>
+      <NavigatorCenterContainer>
+        <NavigationButton isSelected={matchedRoute === '/'} label="Query formatter" href="#/" />
+        <NavigationButton isSelected={matchedRoute === '/style-guide'} label="Style guide" href="#/style-guide" />
+      </NavigatorCenterContainer>
+    </NavigatorWrapper>
+    <Spacer />
+  </div>
+);
+
+export default Navigator;
diff --git a/docs/gremlint/src/components/Paragraph.tsx b/docs/gremlint/src/components/Paragraph.tsx
new file mode 100644
index 0000000..665aef7
--- /dev/null
+++ b/docs/gremlint/src/components/Paragraph.tsx
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+import React from 'react';
+import styled, { css } from 'styled-components';
+import { HTMLAttributes } from 'react';
+import { textColor } from '../styleVariables';
+
+const ParagraphWrapper = styled.div<{ $hasContent: boolean }>`
+  ${({ $hasContent }) =>
+    $hasContent &&
+    css`
+      padding: 10px;
+    `}
+`;
+
+const ParagraphContent = styled.span`
+  color: ${textColor};
+  line-height: 20px;
+  font-size: 15px;
+`;
+
+const Paragraph = ({ children }: HTMLAttributes<HTMLSpanElement>) => (
+  <ParagraphWrapper $hasContent={Boolean(children)}>
+    <ParagraphContent>{children}</ParagraphContent>
+  </ParagraphWrapper>
+);
+
+export default Paragraph;
diff --git a/docs/gremlint/src/components/QueryInput.tsx b/docs/gremlint/src/components/QueryInput.tsx
new file mode 100644
index 0000000..2f95281
--- /dev/null
+++ b/docs/gremlint/src/components/QueryInput.tsx
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+import React from 'react';
+import styled from 'styled-components';
+import { inputTextColor } from '../styleVariables';
+
+const QueryInputWrapper = styled.div`
+  padding: 10px;
+`;
+
+const QueryInputTextArea = styled.textarea`
+  height: calc(100vh / 4);
+  border-radius: 5px;
+  font-family: 'Courier New', Courier, monospace;
+  background: rgba(0, 0, 0, 0.05);
+  outline: none;
+  font-size: 16px;
+  padding: 10px;
+  border: none;
+  resize: none;
+  width: 100%;
+  box-shadow: inset rgba(0, 0, 0, 0.5) 0 0 10px -5px;
+  color: ${inputTextColor};
+  box-sizing: border-box;
+`;
+
+type QueryInputProps = {
+  onChange?: ((event: React.ChangeEvent<HTMLTextAreaElement>) => void) | undefined;
+  value: string;
+};
+
+const QueryInput = ({ onChange, value }: QueryInputProps) => (
+  <QueryInputWrapper>
+    <QueryInputTextArea onChange={onChange} value={value} rows={25} />
+  </QueryInputWrapper>
+);
+
+export default QueryInput;
diff --git a/docs/gremlint/src/components/Spacer.ts b/docs/gremlint/src/components/Spacer.ts
new file mode 100644
index 0000000..a2f12f1
--- /dev/null
+++ b/docs/gremlint/src/components/Spacer.ts
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+import styled from 'styled-components';
+
+const Spacer = styled.div`
+  height: 20px;
+`;
+
+export default Spacer;
diff --git a/docs/gremlint/src/components/StyleGuideRule.tsx b/docs/gremlint/src/components/StyleGuideRule.tsx
new file mode 100644
index 0000000..825bcb7
--- /dev/null
+++ b/docs/gremlint/src/components/StyleGuideRule.tsx
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+import React from 'react';
+import Paragraph from './Paragraph';
+import Title from './Title';
+import CodePreview from './CodePreview';
+import Spacer from './Spacer';
+
+type StyleGuideRuleProps = {
+  title: string;
+  explanation: string;
+  example: string;
+};
+
+const StyleGuideRule = ({ title, explanation, example }: StyleGuideRuleProps) => (
+  <div>
+    <Title>{title}</Title>
+    <Paragraph>{explanation}</Paragraph>
+    <CodePreview>{example}</CodePreview>
+    <Spacer />
+  </div>
+);
+
+export default StyleGuideRule;
diff --git a/docs/gremlint/src/components/TextButton.tsx b/docs/gremlint/src/components/TextButton.tsx
new file mode 100644
index 0000000..6a4ec6a
--- /dev/null
+++ b/docs/gremlint/src/components/TextButton.tsx
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+import React from 'react';
+import styled from 'styled-components';
+import { highlightedTextColor, textColor } from '../styleVariables';
+
+const TextButtonWrapper = styled.span`
+  display: inline-block;
+  padding: 10px;
+  box-sizing: border-box;
+`;
+
+const TextButtonButton = styled.button`
+  height: 20px;
+  line-height: 20px;
+  font-size: 15px;
+  color: ${textColor};
+  &: {
+    color: ${highlightedTextColor};
+  }
+  background: none;
+  border: none;
+  cursor: pointer;
+  padding: 0;
+  outline: none;
+`;
+
+type TextButtonProps = {
+  label: string;
+  onClick: VoidFunction;
+};
+
+const TextButton = ({ label, onClick }: TextButtonProps) => (
+  <TextButtonWrapper>
+    <TextButtonButton onClick={onClick}>{label}</TextButtonButton>
+  </TextButtonWrapper>
+);
+
+export default TextButton;
diff --git a/docs/gremlint/src/components/Title.tsx b/docs/gremlint/src/components/Title.tsx
new file mode 100644
index 0000000..4a8594a
--- /dev/null
+++ b/docs/gremlint/src/components/Title.tsx
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+import React from 'react';
+import styled, { css } from 'styled-components';
+import { HTMLAttributes } from 'react';
+import { textColor } from '../styleVariables';
+
+const TitleWrapper = styled.div<{ $hasContent: boolean }>`
+  ${({ $hasContent }) =>
+    $hasContent &&
+    css`
+      padding: 10px;
+    `}
+`;
+
+const TitleContent = styled.div`
+  color: ${textColor};
+  line-height: 30px;
+  font-size: 25px;
+`;
+
+const Title = ({ children }: HTMLAttributes<HTMLDivElement>) => (
+  <TitleWrapper $hasContent={Boolean(children)}>
+    <TitleContent>{children}</TitleContent>
+  </TitleWrapper>
+);
+
+export default Title;
diff --git a/docs/gremlint/src/components/Toggle.tsx b/docs/gremlint/src/components/Toggle.tsx
new file mode 100644
index 0000000..09adb36
--- /dev/null
+++ b/docs/gremlint/src/components/Toggle.tsx
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+import React from 'react';
+import styled from 'styled-components';
+import { borderColor, highlightedTextColor, textColor, white } from '../styleVariables';
+
+const ToggleContainer = styled.span<{ $width: string; $height: string }>`
+  display: inline-block;
+  height: ${({ $height }) => $height};
+  width: ${({ $width }) => $width};
+  border-radius: 5px;
+  background: rgba(0, 0, 0, 0.05);
+  box-shadow: inset rgba(0, 0, 0, 0.5) 0 0 10px -5px;
+  position: relative;
+`;
+
+const Option = styled.span<{ $width: string; $height: string }>`
+  cursor: pointer;
+  display: inline-block;
+  height: ${({ $height }) => $height};
+  width: calc(${({ $width }) => $width} / 2);
+  box-sizing: border-box;
+  padding: 10px;
+  line-height: 20px;
+  font-size: 16px;
+  color: ${textColor};
+  text-align: center;
+`;
+
+const SelectedOption = styled.span<{ $checked: boolean }>`
+  background: ${white};
+  cursor: pointer;
+  display: inline-block;
+  position: absolute;
+  top: 0;
+  left: ${({ $checked }) => ($checked ? '160px' : '0')};
+  height: 40px;
+  width: 160px;
+  border-radius: 5px;
+  box-sizing: border-box;
+  padding: 10px;
+  line-height: 20px;
+  font-size: 16px;
+  color: ${highlightedTextColor};
+  text-align: center;
+  border: 1px solid ${borderColor};
+  transition: 0.5s;
+`;
+
+type ToggleProps = {
+  width: string;
+  height: string;
+  checked: boolean;
+  labels: { checked: string; unchecked: string };
+  onChange: (checked: boolean) => void;
+};
+
+const Toggle = ({
+  width = '320px',
+  height = '40px',
+  checked = false,
+  labels = { checked: 'Checked', unchecked: 'Unchecked' },
+  onChange,
+}: ToggleProps) => (
+  <ToggleContainer $width={width} $height={height}>
+    <Option $width={width} $height={height} onClick={() => onChange(false)}>
+      {labels.unchecked}
+    </Option>
+    <Option $width={width} $height={height} onClick={() => onChange(true)}>
+      {labels.checked}
+    </Option>
+    <SelectedOption $checked={checked}>{checked ? labels.checked : labels.unchecked}</SelectedOption>
+  </ToggleContainer>
+);
+
+export default Toggle;
diff --git a/docs/gremlint/src/gremlint-loading-logo-colored.png b/docs/gremlint/src/gremlint-loading-logo-colored.png
new file mode 100644
index 0000000..9439d45
--- /dev/null
+++ b/docs/gremlint/src/gremlint-loading-logo-colored.png
Binary files differ
diff --git a/docs/gremlint/src/gremlint-loading-logo-grayscale.png b/docs/gremlint/src/gremlint-loading-logo-grayscale.png
new file mode 100644
index 0000000..4799023
--- /dev/null
+++ b/docs/gremlint/src/gremlint-loading-logo-grayscale.png
Binary files differ
diff --git a/docs/gremlint/src/index.css b/docs/gremlint/src/index.css
new file mode 100644
index 0000000..29feab3
--- /dev/null
+++ b/docs/gremlint/src/index.css
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+body {
+  margin: 0;
+  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans',
+    'Droid Sans', 'Helvetica Neue', sans-serif;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+code {
+  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
+}
diff --git a/docs/gremlint/src/index.tsx b/docs/gremlint/src/index.tsx
new file mode 100644
index 0000000..6f9a685
--- /dev/null
+++ b/docs/gremlint/src/index.tsx
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+import React from 'react';
+import ReactDOM from 'react-dom';
+import './index.css';
+import App from './App';
+import reportWebVitals from './reportWebVitals';
+
+ReactDOM.render(
+  <React.StrictMode>
+    <App />
+  </React.StrictMode>,
+  document.getElementById('root'),
+);
+
+// If you want to start measuring performance in your app, pass a function
+// to log results (for example: reportWebVitals(console.log))
+// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
+reportWebVitals();
diff --git a/docs/gremlint/src/libs/reduced-state/dispatch.ts b/docs/gremlint/src/libs/reduced-state/dispatch.ts
new file mode 100644
index 0000000..554473e
--- /dev/null
+++ b/docs/gremlint/src/libs/reduced-state/dispatch.ts
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+export const dispatch = (action: string, payload?: any) => {
+  window.dispatchEvent(new CustomEvent(action, { detail: payload }));
+};
diff --git a/docs/gremlint/src/libs/reduced-state/index.ts b/docs/gremlint/src/libs/reduced-state/index.ts
new file mode 100644
index 0000000..f16ecb5
--- /dev/null
+++ b/docs/gremlint/src/libs/reduced-state/index.ts
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+export { dispatch } from './dispatch';
+export { default } from './reducedState';
diff --git a/docs/gremlint/src/libs/reduced-state/reducedState.ts b/docs/gremlint/src/libs/reduced-state/reducedState.ts
new file mode 100644
index 0000000..c57e8dd
--- /dev/null
+++ b/docs/gremlint/src/libs/reduced-state/reducedState.ts
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+import { ChangeListener, CreateReducedStateProps } from './types';
+
+const createReducedState = <T>({ initialState, reducers, routines }: CreateReducedStateProps<T>) => {
+  let state = initialState;
+  let changeListeners: ChangeListener<T>[] = [];
+
+  Object.entries(reducers).forEach(([action, reducer]) => {
+    window.addEventListener(action, ((event: CustomEvent) => {
+      const nextState = reducer(state, event.detail);
+      state = nextState;
+      changeListeners.forEach((changeListener) => changeListener(state));
+    }) as EventListener);
+  });
+
+  Object.entries(routines).forEach(([action, routine]) => {
+    window.addEventListener(action, ((event: CustomEvent) => {
+      routine(state, event.detail);
+    }) as EventListener);
+  });
+
+  const addChangeListener = (changeListenerToBeAdded: ChangeListener<T>) => {
+    changeListeners = [...changeListeners, changeListenerToBeAdded];
+  };
+
+  const removeChangeListener = (changeListenerToBeRemoved: ChangeListener<T>) => {
+    changeListeners = changeListeners.filter((changeListener) => changeListener !== changeListenerToBeRemoved);
+  };
+
+  return { state, addChangeListener, removeChangeListener };
+};
+
+export default createReducedState;
diff --git a/docs/gremlint/src/libs/reduced-state/types.ts b/docs/gremlint/src/libs/reduced-state/types.ts
new file mode 100644
index 0000000..b6f9b4a
--- /dev/null
+++ b/docs/gremlint/src/libs/reduced-state/types.ts
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+export type Reducer<T> = (state: T, payload: any) => T;
+
+export type Routine<T> = (state: T, payload: any) => void;
+
+export type CreateReducedStateProps<T> = {
+  initialState: T;
+  reducers: Record<string, Reducer<T>>;
+  routines: Record<string, Routine<T>>;
+};
+
+export type ChangeListener<T> = (state: T) => void;
+
+export type ReducedState<T> = {
+  state: T;
+  addChangeListener: (changeListenerToBeAdded: ChangeListener<T>) => void;
+  removeChangeListener: (changeListenerToBeRemoved: ChangeListener<T>) => void;
+};
diff --git a/docs/gremlint/src/libs/reduced-state/useReducedState.ts b/docs/gremlint/src/libs/reduced-state/useReducedState.ts
new file mode 100644
index 0000000..b41f927
--- /dev/null
+++ b/docs/gremlint/src/libs/reduced-state/useReducedState.ts
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+import { useEffect, useState } from 'react';
+import { ReducedState } from './types';
+
+export const useReducedState = <T>(reducedState: ReducedState<T>) => {
+  const [state, setState] = useState<T>(reducedState.state);
+
+  useEffect(() => {
+    const changeListener = (state: T) => {
+      setState(state);
+    };
+    reducedState.addChangeListener(changeListener);
+    return () => reducedState.removeChangeListener(changeListener);
+  }, [reducedState]);
+
+  return state;
+};
diff --git a/docs/gremlint/src/react-app-env.d.ts b/docs/gremlint/src/react-app-env.d.ts
new file mode 100644
index 0000000..8afae96
--- /dev/null
+++ b/docs/gremlint/src/react-app-env.d.ts
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/// <reference types="react-scripts" />
diff --git a/docs/gremlint/src/reportWebVitals.ts b/docs/gremlint/src/reportWebVitals.ts
new file mode 100644
index 0000000..cd38d72
--- /dev/null
+++ b/docs/gremlint/src/reportWebVitals.ts
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+import { ReportHandler } from 'web-vitals';
+
+const reportWebVitals = (onPerfEntry?: ReportHandler) => {
+  if (onPerfEntry && onPerfEntry instanceof Function) {
+    import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
+      getCLS(onPerfEntry);
+      getFID(onPerfEntry);
+      getFCP(onPerfEntry);
+      getLCP(onPerfEntry);
+      getTTFB(onPerfEntry);
+    });
+  }
+};
+
+export default reportWebVitals;
diff --git a/docs/gremlint/src/router.ts b/docs/gremlint/src/router.ts
new file mode 100644
index 0000000..29e47d5
--- /dev/null
+++ b/docs/gremlint/src/router.ts
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+import createRouter from 'sharp-router';
+
+const router = createRouter({
+  '/': 'Gremlint - Query formatter',
+  '/style-guide': 'Gremlint - Style guide',
+});
+
+export default router;
diff --git a/docs/gremlint/src/setupTests.ts b/docs/gremlint/src/setupTests.ts
new file mode 100644
index 0000000..59fdb48
--- /dev/null
+++ b/docs/gremlint/src/setupTests.ts
@@ -0,0 +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
+ *
+ * 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.
+ */
+
+// jest-dom adds custom jest matchers for asserting on DOM nodes.
+// allows you to do things like:
+// expect(element).toHaveTextContent(/react/i)
+// learn more: https://github.com/testing-library/jest-dom
+import '@testing-library/jest-dom';
diff --git a/docs/gremlint/src/store/actions.ts b/docs/gremlint/src/store/actions.ts
new file mode 100644
index 0000000..c0979a6
--- /dev/null
+++ b/docs/gremlint/src/store/actions.ts
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+export const SET_QUERY_INPUT = 'SET_QUERY_INPUT';
+export const FORMAT_QUERY = 'FORMAT_QUERY';
+export const TOGGLE_SHOULD_SHOW_ADVANCED_OPTIONS = 'TOGGLE_SHOULD_SHOW_ADVANCED_OPTIONS';
+export const SET_INDENTATION = 'SET_INDENTATION';
+export const SET_MAX_LINE_LENGTH = 'SET_MAX_LINE_LENGTH';
+export const SET_SHOULD_PLACE_DOTS_AFTER_LINE_BREAKS = 'SET_SHOULD_PLACE_DOTS_AFTER_LINE_BREAKS';
diff --git a/docs/gremlint/src/store/index.ts b/docs/gremlint/src/store/index.ts
new file mode 100644
index 0000000..b63ccfb
--- /dev/null
+++ b/docs/gremlint/src/store/index.ts
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+import createReducedState from '../libs/reduced-state';
+import initialState from './initialState';
+import reducers from './reducers';
+import routines from './routines';
+
+const store = createReducedState({ initialState, reducers, routines });
+
+export default store;
diff --git a/docs/gremlint/src/store/initialState.ts b/docs/gremlint/src/store/initialState.ts
new file mode 100644
index 0000000..30bbfa1
--- /dev/null
+++ b/docs/gremlint/src/store/initialState.ts
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+const initialState = {
+  queryInput: '',
+  queryOutput: '',
+  shouldShowAdvancedOptions: false,
+  indentation: 0,
+  maxLineLength: 72,
+  shouldPlaceDotsAfterLineBreaks: false,
+};
+
+export default initialState;
diff --git a/docs/gremlint/src/store/reducers.ts b/docs/gremlint/src/store/reducers.ts
new file mode 100644
index 0000000..01471bf
--- /dev/null
+++ b/docs/gremlint/src/store/reducers.ts
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+import { formatQuery } from 'gremlint';
+import {
+  FORMAT_QUERY,
+  SET_INDENTATION,
+  SET_MAX_LINE_LENGTH,
+  SET_QUERY_INPUT,
+  SET_SHOULD_PLACE_DOTS_AFTER_LINE_BREAKS,
+  TOGGLE_SHOULD_SHOW_ADVANCED_OPTIONS,
+} from './actions';
+import { State } from './types';
+
+const handleSetQueryInput = (state: State, queryInput: string) => ({
+  ...state,
+  queryInput,
+});
+
+const handleFormatQuery = (state: State) => ({
+  ...state,
+  queryOutput: formatQuery(state.queryInput, {
+    indentation: state.indentation,
+    maxLineLength: state.maxLineLength,
+    shouldPlaceDotsAfterLineBreaks: state.shouldPlaceDotsAfterLineBreaks,
+  }),
+});
+
+const handleToggleShouldShowAdvancedOptions = (state: State) => ({
+  ...state,
+  shouldShowAdvancedOptions: !state.shouldShowAdvancedOptions,
+});
+
+const handleSetIndentation = (state: State, unparsedIndentation: string) => {
+  const indentation = parseInt(unparsedIndentation);
+  if (isNaN(indentation)) return { ...state };
+  if (indentation < 0) return { ...state, indentation: 0 };
+  const { maxLineLength } = state;
+  if (indentation > maxLineLength) {
+    return { ...state, indentation: maxLineLength };
+  }
+  return { ...state, indentation };
+};
+
+const handleSetMaxLineLength = (state: State, unparsedMaxLineLength: string) => {
+  const maxLineLength = parseInt(unparsedMaxLineLength);
+  if (isNaN(maxLineLength)) return { ...state };
+  const { indentation } = state;
+  if (maxLineLength < indentation) {
+    return { ...state, maxLineLength: indentation };
+  }
+  return { ...state, maxLineLength };
+};
+
+const handleSetShouldPlaceDotsAfterLineBreaks = (state: State, shouldPlaceDotsAfterLineBreaks: boolean) => ({
+  ...state,
+  shouldPlaceDotsAfterLineBreaks,
+});
+
+const reducers = {
+  [SET_QUERY_INPUT]: handleSetQueryInput,
+  [FORMAT_QUERY]: handleFormatQuery,
+  [TOGGLE_SHOULD_SHOW_ADVANCED_OPTIONS]: handleToggleShouldShowAdvancedOptions,
+  [SET_INDENTATION]: handleSetIndentation,
+  [SET_MAX_LINE_LENGTH]: handleSetMaxLineLength,
+  [SET_SHOULD_PLACE_DOTS_AFTER_LINE_BREAKS]: handleSetShouldPlaceDotsAfterLineBreaks,
+};
+
+export default reducers;
diff --git a/docs/gremlint/src/store/routines.ts b/docs/gremlint/src/store/routines.ts
new file mode 100644
index 0000000..d0bca5c
--- /dev/null
+++ b/docs/gremlint/src/store/routines.ts
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+import { dispatch } from '../libs/reduced-state';
+import {
+  SET_QUERY_INPUT,
+  FORMAT_QUERY,
+  SET_INDENTATION,
+  SET_MAX_LINE_LENGTH,
+  SET_SHOULD_PLACE_DOTS_AFTER_LINE_BREAKS,
+} from './actions';
+
+const handleSetQueryInput = () => dispatch(FORMAT_QUERY);
+const handleSetIndentation = () => dispatch(FORMAT_QUERY);
+const handleSetMaxLineLength = () => dispatch(FORMAT_QUERY);
+const handleSetShouldPlaceDotsAfterLineBreaks = () => dispatch(FORMAT_QUERY);
+
+const routines = {
+  [SET_QUERY_INPUT]: handleSetQueryInput,
+  [SET_INDENTATION]: handleSetIndentation,
+  [SET_MAX_LINE_LENGTH]: handleSetMaxLineLength,
+  [SET_SHOULD_PLACE_DOTS_AFTER_LINE_BREAKS]: handleSetShouldPlaceDotsAfterLineBreaks,
+};
+
+export default routines;
diff --git a/docs/gremlint/src/store/types.ts b/docs/gremlint/src/store/types.ts
new file mode 100644
index 0000000..dd5f8b1
--- /dev/null
+++ b/docs/gremlint/src/store/types.ts
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+export type State = {
+  queryInput: string;
+  queryOutput: string;
+  shouldShowAdvancedOptions: boolean;
+  indentation: number;
+  maxLineLength: number;
+  shouldPlaceDotsAfterLineBreaks: boolean;
+};
diff --git a/docs/gremlint/src/styleVariables.ts b/docs/gremlint/src/styleVariables.ts
new file mode 100644
index 0000000..55c2f28
--- /dev/null
+++ b/docs/gremlint/src/styleVariables.ts
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+export const borderColor = 'lightgray';
+export const textColor = 'slategray';
+export const inputTextColor = 'darkslategray';
+export const highlightedTextColor = 'darkslategray';
+export const disabledTextColor = 'lightgray';
+export const highlightColor = 'yellowgreen';
+export const white = 'white';
diff --git a/docs/gremlint/src/views/QueryFormatter/AdvancedOptions.tsx b/docs/gremlint/src/views/QueryFormatter/AdvancedOptions.tsx
new file mode 100644
index 0000000..529e459
--- /dev/null
+++ b/docs/gremlint/src/views/QueryFormatter/AdvancedOptions.tsx
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+
+import React from 'react';
+import styled from 'styled-components';
+import { dispatch } from '../../libs/reduced-state';
+import { useReducedState } from '../../libs/reduced-state/useReducedState';
+import store from '../../store';
+import { SET_INDENTATION, SET_MAX_LINE_LENGTH, SET_SHOULD_PLACE_DOTS_AFTER_LINE_BREAKS } from '../../store/actions';
+import { inputTextColor, textColor } from '../../styleVariables';
+import Toggle from '../../components/Toggle';
+
+const AdvancedOptionRowWrapper = styled.div`
+  padding: 10px;
+`;
+
+const AdvancedOptionLabel = styled.div`
+  height: 20px;
+  line-height: 20px;
+  font-size: 15px;
+  color: ${textColor};
+`;
+
+const AdvancedOptionInput = styled.input`
+  border-radius: 5px;
+  background: rgba(0, 0, 0, 0.05);
+  outline: none;
+  font-size: 16px;
+  padding: 10px;
+  border: none;
+  box-shadow: inset rgba(0, 0, 0, 0.5) 0 0 10px -5px;
+  color: ${inputTextColor};
+  display: inline-block;
+  vertical-align: bottom;
+  box-sizing: border-box;
+  height: 40px;
+  width: 320px;
+`;
+
+const AdvancedOptions = () => {
+  const state = useReducedState(store);
+  return (
+    <div>
+      <AdvancedOptionRowWrapper>
+        <AdvancedOptionLabel>Indentation</AdvancedOptionLabel>
+        <AdvancedOptionInput
+          type="number"
+          min={0}
+          max={state.maxLineLength}
+          value={state.indentation}
+          onChange={({ target }) => {
+            dispatch(SET_INDENTATION, target.value);
+          }}
+        />
+      </AdvancedOptionRowWrapper>
+      <AdvancedOptionRowWrapper>
+        <AdvancedOptionLabel>Max line length</AdvancedOptionLabel>
+        <AdvancedOptionInput
+          type="number"
+          min={state.indentation}
+          value={state.maxLineLength}
+          onChange={({ target }) => {
+            dispatch(SET_MAX_LINE_LENGTH, target.value);
+          }}
+        />
+      </AdvancedOptionRowWrapper>
+      <AdvancedOptionRowWrapper>
+        <AdvancedOptionLabel>Dot placement</AdvancedOptionLabel>
+        <Toggle
+          height="40px"
+          width="320px"
+          checked={state.shouldPlaceDotsAfterLineBreaks}
+          labels={{
+            checked: 'After line break',
+            unchecked: 'Before line break',
+          }}
+          onChange={(shouldPlaceDotsAfterLineBreaks) => {
+            dispatch(SET_SHOULD_PLACE_DOTS_AFTER_LINE_BREAKS, shouldPlaceDotsAfterLineBreaks);
+          }}
+        />
+      </AdvancedOptionRowWrapper>
+    </div>
+  );
+};
+
+export default AdvancedOptions;
diff --git a/docs/gremlint/src/views/QueryFormatter/index.tsx b/docs/gremlint/src/views/QueryFormatter/index.tsx
new file mode 100644
index 0000000..c2214f1
--- /dev/null
+++ b/docs/gremlint/src/views/QueryFormatter/index.tsx
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+import React from 'react';
+import styled from 'styled-components';
+import store from '../../store';
+import QueryInput from '../../components/QueryInput';
+import TextButton from '../../components/TextButton';
+import CodePreview from '../../components/CodePreview';
+import AdvancedOptions from './AdvancedOptions';
+import { State } from '../../store/types';
+import { dispatch } from '../../libs/reduced-state';
+import { useReducedState } from '../../libs/reduced-state/useReducedState';
+import { SET_QUERY_INPUT, TOGGLE_SHOULD_SHOW_ADVANCED_OPTIONS } from '../../store/actions';
+
+const ExpandableAdvancedOptionsWrapper = styled.div<{ $isExpanded: boolean }>`
+  max-height: ${({ $isExpanded }) => ($isExpanded ? '240px' : '0')};
+  box-shadow: inset white 0 0 10px 0;
+  overflow: hidden;
+  transition: 0.5s;
+`;
+
+const QueryFormatter = () => {
+  const state = useReducedState<State>(store);
+  return (
+    <div>
+      <QueryInput value={state.queryInput} onChange={({ target }) => dispatch(SET_QUERY_INPUT, target.value)} />
+      <TextButton
+        label={state.shouldShowAdvancedOptions ? 'Hide advanced options' : 'Show advanced options'}
+        onClick={() => dispatch(TOGGLE_SHOULD_SHOW_ADVANCED_OPTIONS)}
+      />
+      <ExpandableAdvancedOptionsWrapper $isExpanded={state.shouldShowAdvancedOptions}>
+        <AdvancedOptions />
+      </ExpandableAdvancedOptionsWrapper>
+      {state.queryOutput ? <CodePreview maxLineLength={state.maxLineLength}>{state.queryOutput}</CodePreview> : null}
+    </div>
+  );
+};
+
+export default QueryFormatter;
diff --git a/docs/gremlint/src/views/StyleGuide/index.tsx b/docs/gremlint/src/views/StyleGuide/index.tsx
new file mode 100644
index 0000000..b83574c
--- /dev/null
+++ b/docs/gremlint/src/views/StyleGuide/index.tsx
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+import React from 'react';
+import StyleGuideRule from '../../components/StyleGuideRule';
+import { rules } from './rules';
+
+const StyleGuide = () => (
+  <div>
+    {rules.map(({ title, explanation, example }) => (
+      <StyleGuideRule key={title} title={title} explanation={explanation} example={example} />
+    ))}
+  </div>
+);
+
+export default StyleGuide;
diff --git a/docs/gremlint/src/views/StyleGuide/rules.ts b/docs/gremlint/src/views/StyleGuide/rules.ts
new file mode 100644
index 0000000..a7220d6
--- /dev/null
+++ b/docs/gremlint/src/views/StyleGuide/rules.ts
@@ -0,0 +1,304 @@
+/*
+ * 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.
+ */
+
+export const rules = [
+  {
+    title: 'Break long queries into multiple lines',
+    explanation: `What is considered too long depends on your application.
+When breaking the query, not all parts of the traversal have to be broken up. First, divide the query into logical groups, based on which steps belong naturally together. For instance, every set of steps which end with an as()-step often belong together, as they together form a new essential step in the query.
+    
+If anoymous traversals are passed as arguments to another step, like a filter()-step, and it's causing the line to be too long, first split the line at the commas. Only if the traversal arguments are still too long, consider splitting them further.`,
+    example: `// Good (80 characters max width)
+g.V().hasLabel('person').where(outE("created").count().is(P.gte(2))).count()
+    
+// Good (50 characters max width)
+g.V().
+  hasLabel('person').
+  where(outE("created").count().is(P.gte(2))).
+  count()
+    
+// Good (30 characters max width)
+g.V().
+  hasLabel('person').
+  where(
+    outE("created").
+    count().
+    is(P.gte(2))).
+  count()`,
+  },
+  {
+    title: 'Use soft tabs (spaces) for indentation',
+    explanation: 'This ensures that your code looks the same for anyone, regardless of their text editor settings.',
+    example: `// Bad - indented using hard tabs
+g.V().
+  hasLabel('person').as('person').
+  properties('location').as('location').
+  select('person','location').
+    by('name').
+    by(valueMap())
+    
+// Good - indented using spaces
+g.V().
+∙∙hasLabel('person').as('person').
+∙∙properties('location').as('location').
+∙∙select('person','location').
+∙∙∙∙by('name').
+∙∙∙∙by(valueMap())`,
+  },
+  {
+    title: 'Use two spaces for indentation',
+    explanation:
+      'Two spaces makes the intent of the indent clear, but does not waste too much space. Of course, more spaces are allowed when indenting from an already indented block of code.',
+    example: `// Bad - Indented using four spaces
+g.V().
+    hasLabel('person').as('person').
+    properties('location').as('location').
+    select('person','location').
+        by('name').
+        by(valueMap())
+// Good - Indented using two spaces
+g.V().
+  hasLabel('person').as('person').
+  properties('location').as('location').
+  select('person','location').
+    by('name').
+    by(valueMap())`,
+  },
+  {
+    title: 'Use indents wisely',
+    explanation: `No newline should ever have the same indent as the line starting with the traversal source g.
+Use indents when the step in the new line is a modulator of a previous line.
+Use indents when the content in the new line is an argument of a previous step.
+If multiple anonymous traversals are passed as arguments to a function, each newline which is not the first step of the traversal should be indented to make it more clear where the distinction between each argument goes. If this is the case, but the newline would already be indented because the step in the content in the new line is the argument of a previous step, there is no need to double-indent.
+Don't be tempted to add extra indentation to vertically align a step with a step in a previous line.`,
+    example: `// Bad - No newline should have the same indent as the line starting with the traversal source g
+g.V().
+group().
+by().
+by(bothE().count())
+// Bad - Modulators of a step on a previous line should be indented
+g.V().
+  group().
+  by().
+  by(bothE().count())
+// Good
+g.V().
+  group().
+    by().
+    by(bothE().count())
+// Bad - You have ignored the indent rules to achieve the temporary satisfaction of vertical alignment
+g.V().local(union(identity(),
+                  bothE().count()).
+            fold())
+// Good
+g.V().
+  local(
+    union(
+      identity(),
+      bothE().count()).
+    fold())
+// Bad - When multiple anonymous traversals are passed as arguments to a function, each newline which is not the first of line of the step should be indented to make it more clear where the distinction between each argument goes.
+g.V().
+  has('person','name','marko').
+  fold().
+  coalesce(
+    unfold(),
+    addV('person').
+    property('name','marko').
+    property('age',29))
+// Good - We make it clear that the coalesce step takes two traversals as arguments
+g.V().
+  has('person','name','marko').
+  fold().
+  coalesce(
+    unfold(),
+    addV('person').
+      property('name','marko').
+      property('age',29))`,
+  },
+  {
+    title: 'Keep as()-steps at the end of each line',
+    explanation: `The end of the line is a natural place to assign a label to a step. It's okay if the as()-step is in the middle of the line if there are multiple consecutive label assignments, or if the line is so short that a newline doesn't make sense. Maybe a better way to put it is to not start a line with an as()-step, unless you're using it inside a match()-step of course.`,
+    example: `// Bad
+g.V().
+  as('a').
+  out('created').
+  as('b').
+  select('a','b')
+// Good
+g.V().as('a').
+  out('created').as('b').
+  select('a','b')
+// Good
+g.V().as('a').out('created').as('b').select('a','b')`,
+  },
+  {
+    title: 'Add linebreak after punctuation, not before',
+    explanation: `While adding the linebreak before the punctuation looks good in most cases, it introduces alignment problems when not all lines start with a punctuation. You never know if the next line should be indented relative to the punctuation of the previous line or the method of the previous line. Switching between having the punctuation at the start or the end of the line depending on whether it works in a particular case requires much brainpower (which we don't have), so it's better to be consistent. Adding the punctuation before the linebreak also means that you can know if you have reached the end of the query without reading the next line.`,
+    example: `// Bad - Looks okay, though
+g.V().has('name','marko')
+     .out('knows')
+     .has('age', gt(29))
+     .values('name')
+// Good
+g.V().
+  has('name','marko').
+  out('knows').
+  has('age', gt(29)).
+  values('name')
+// Bad - Punctuation at the start of the line makes the transition from filter to select to count too smooth
+g.V()
+  .hasLabel("person")
+  .group()
+    .by(values("name", "age").fold())
+  .unfold()
+  .filter(
+    select(values)
+    .count(local)
+    .is(gt(1)))
+// Good - Keeping punctuation at the end of each line, more clearly shows the query structure
+g.V().
+  hasLabel("person").
+  group().
+    by(values("name", "age").fold()).
+  unfold().
+  filter(
+    select(values).
+    count(local).
+    is(gt(1)))`,
+  },
+  {
+    title: 'Add linebreak and indentation for nested traversals which are long enough to span multiple lines',
+    explanation: '',
+    example: `// Bad - Not newlining the first argument of a function whose arguments span over multipe lines causes the arguments to not align.
+g.V().
+  hasLabel("person").
+  groupCount().
+    by(values("age").
+      choose(is(lt(28)),
+        constant("young"),
+        choose(is(lt(30)),
+          constant("old"),
+          constant("very old"))))
+// Bad - We talked about this in the indentation section, didn't we?
+g.V().
+  hasLabel("person").
+  groupCount().
+    by(values("age").
+       choose(is(lt(28)),
+              constant("young"),
+              choose(is(lt(30)),
+                     constant("old"),
+                     constant("very old"))))
+// Good
+g.V().
+  hasLabel("person").
+  groupCount().
+    by(
+      values("age").
+      choose(
+        is(lt(28)),
+        constant("young"),
+        choose(
+          is(lt(30)),
+          constant("old"),
+          constant("very old"))))`,
+  },
+  {
+    title: 'Place all trailing parentheses on a single line instead of distinct lines',
+    explanation:
+      'Aligning the end parenthesis with the step to which the start parenthesis belongs might make it easier to check that the number of parentheses is correct, but looks ugly and wastes a lot of space.',
+    example: `// Bad
+g.V().
+  hasLabel("person").
+  groupCount().
+    by(
+      values("age").
+      choose(
+        is(lt(28)),
+        constant("young"),
+        choose(
+          is(lt(30)),
+          constant("old"),
+          constant("very old")
+        )
+      )
+    )
+// Good
+g.V().
+  hasLabel("person").
+  groupCount().
+    by(
+      values("age").
+      choose(
+        is(lt(28)),
+        constant("young"),
+        choose(
+          is(lt(30)),
+          constant("old"),
+          constant("very old"))))`,
+  },
+  {
+    title: 'Use // for single line comments. Place single line comments on a newline above the subject of the comment.',
+    explanation: '',
+    example: `// Bad
+g.V().
+  has('name','alice').out('bought'). // Find everything that Alice has bought
+  in('bought').dedup().values('name') // Find everyone who have bought some of the same things as Alice
+// Good
+g.V().
+  // Find everything that Alice has bought
+  has('name','alice').out('bought').
+  // Find everyone who have bought some of the same things as Alice
+  in('bought').dedup().values('name')`,
+  },
+  {
+    title: 'Use single quotes for strings',
+    explanation:
+      'Use single quotes for literal string values. If the string contains double quotes or single quotes, surround the string with the type of quote which creates the fewest escaped characters.',
+    example: `// Bad - Use single quotes where possible
+g.V().has("Movie", "name", "It's a wonderful life")
+// Bad - Escaped single quotes are even worse than double quotes
+g.V().has('Movie', 'name', 'It\\'s a wonderful life')
+// Good
+g.V().has('Movie', 'name', "It's a wonderful life")`,
+  },
+  {
+    title: 'Write idiomatic Gremlin code',
+    explanation: `If there is a simpler way, do it the simpler way. Use the Gremlin methods for what they're worth.`,
+    example: `// Bad
+g.V().outE().inV()
+// Good
+g.V().out()
+// Bad
+g.V().
+  has('name', 'alice').
+  outE().hasLabel('bought').inV().
+  values('name')
+// Good
+g.V().
+  has('name','alice').
+  out('bought').
+  values('name')
+// Bad
+g.V().hasLabel('person').has('name', 'alice')
+// Good
+g.V().has('person', 'name', 'alice')`,
+  },
+];
diff --git a/docs/gremlint/tsconfig.json b/docs/gremlint/tsconfig.json
new file mode 100644
index 0000000..a273b0c
--- /dev/null
+++ b/docs/gremlint/tsconfig.json
@@ -0,0 +1,26 @@
+{
+  "compilerOptions": {
+    "target": "es5",
+    "lib": [
+      "dom",
+      "dom.iterable",
+      "esnext"
+    ],
+    "allowJs": true,
+    "skipLibCheck": true,
+    "esModuleInterop": true,
+    "allowSyntheticDefaultImports": true,
+    "strict": true,
+    "forceConsistentCasingInFileNames": true,
+    "noFallthroughCasesInSwitch": true,
+    "module": "esnext",
+    "moduleResolution": "node",
+    "resolveJsonModule": true,
+    "isolatedModules": true,
+    "noEmit": true,
+    "jsx": "react-jsx"
+  },
+  "include": [
+    "src"
+  ]
+}
diff --git a/docs/gremlint/tslint.json b/docs/gremlint/tslint.json
new file mode 100644
index 0000000..267f369
--- /dev/null
+++ b/docs/gremlint/tslint.json
@@ -0,0 +1,3 @@
+{
+  "extends": ["tslint:recommended", "tslint-config-prettier"]
+}
diff --git a/docs/postprocessor/postprocess.sh b/docs/postprocessor/postprocess.sh
index b2d4971..e7dca52 100755
--- a/docs/postprocessor/postprocess.sh
+++ b/docs/postprocessor/postprocess.sh
@@ -23,6 +23,10 @@
 TP_VERSION=$(cat pom.xml | grep -A1 '<artifactId>tinkerpop</artifactId>' | grep -o 'version>[^<]*' | grep -o '>.*' | cut -d '>' -f2 | head -n1)
 
 if [ -d "target/docs" ]; then
+
+  # redirect the GLV Tutorial to reference docs
+  sed -i "s/<meta charset=\"UTF-8\">/<meta http-equiv=\"Refresh\" content=\"0; url='https:\/\/tinkerpop.apache.org\/docs\/x.y.z\/reference\/#gremlin-drivers-variants'\" \/>/" target/docs/htmlsingle/tutorials/gremlin-language-variants/index.html
+
   find target/docs -name index.html | while read file ; do
     awk -f "docs/postprocessor/processor.awk" "${file}" 2>/dev/null       \
       | perl -0777 -pe 's/<span class="comment">\/\*\n \*\/<\/span>//igs' \
diff --git a/docs/preprocessor/awk/init-code-blocks.awk b/docs/preprocessor/awk/init-code-blocks.awk
index b5d00b4..c9eb528 100644
--- a/docs/preprocessor/awk/init-code-blocks.awk
+++ b/docs/preprocessor/awk/init-code-blocks.awk
@@ -50,48 +50,6 @@
     print "f = new File('/tmp/tinkergraph.kryo')"
     print "if (f.exists()) f.deleteDir()"
     print ":set max-iteration 100"
-    if (lang == "python") {
-      print "import static javax.script.ScriptContext.*"
-      print "import org.apache.tinkerpop.gremlin.python.jsr223.JythonTranslator"
-      print "jython = new org.apache.tinkerpop.gremlin.python.jsr223.GremlinJythonScriptEngine()"
-      print "jython.eval('import os')"
-      print "jython.eval('os.chdir(\"" TP_HOME "\")')"
-      print "jython.eval('import sys')"
-      print "jython.eval('sys.path.append(\"" PYTHONPATH "\")')"
-      print "jython.eval('sys.path.append(\"" TP_HOME "/gremlin-python/target/python2/env/lib/python2.7/site-packages\")')"
-      print "jython.eval('from gremlin_python import statics')"
-      print "jython.eval('from gremlin_python.process.traversal import *')"
-      print "jython.eval('from gremlin_python.process.strategies import *')"
-      print "jython.eval('from gremlin_python.structure.graph import Graph')"
-      print "jython.eval('from gremlin_python.structure.io.graphsonV3d0 import GraphSONWriter')"
-      print "jython.eval('from gremlin_python.structure.io.graphsonV3d0 import GraphSONReader')"
-      # print "jython.eval('from gremlin_python.structure.io.graphson import serializers')"
-      # print "jython.eval('from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection')"
-      print "jython.eval('statics.load_statics(globals())')"
-      print "jythonBindings = jython.createBindings()"
-      print "jythonBindings.put('g', jython.eval('Graph().traversal()'))"
-      print "jythonBindings.put('h', g)"
-      print "jython.getContext().setBindings(jythonBindings, GLOBAL_SCOPE)"
-      print "groovy = new org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine()"
-      print "groovyBindings = groovy.createBindings()"
-      print "groovyBindings.put('g', g)"
-      print "groovyBindings.put('TinkerGraphComputer', TinkerGraphComputer)"
-      print "groovy.getContext().setBindings(groovyBindings, GLOBAL_SCOPE)"
-      print "def processTraversal(t, jython, groovy) {"
-      print "  jython.getContext().getBindings(GLOBAL_SCOPE).put('j', jython.eval(t.replace('.toList()','')))"
-      print "  if(jython.eval('isinstance(j, Traversal)')) {"
-      print "    mapper = GraphSONMapper.build().version(GraphSONVersion.V2_0).create().createMapper()"
-      print "    bytecode = mapper.readValue(jython.eval('GraphSONWriter().writeObject(j)').toString(), Bytecode.class)"
-      print "    language = BytecodeHelper.getLambdaLanguage(bytecode).orElse('gremlin-groovy')"
-      print "    result = language.equals('gremlin-groovy') ? groovy.eval(org.apache.tinkerpop.gremlin.process.traversal.translator.GroovyTranslator.of(\"g\").translate(bytecode) + '.toList()').toString() : jython.eval(JythonTranslator.of(\"h\").translate(bytecode) + '.toList()').toString()"
-      print "    jython.getContext().getBindings(GLOBAL_SCOPE).put('json', mapper.writeValueAsString(result))"
-      print "    return jython.eval('GraphSONReader().readObject(json)').toString()"
-      print "  } else {"
-      print "    j = jython.getContext().getBindings(GLOBAL_SCOPE).get('j')"
-      print "    return null == j ? 'null' : j.toString()"
-      print "  }"
-      print "}"
-    }
   }
   print "'-IGNORE'"
 }
@@ -99,9 +57,6 @@
 !/^pb\([0-9]*\); '\[gremlin-/ {
   if (delimiter == 2 && !($0 ~ /^pb\([0-9]*\); '----'/)) {
     switch (lang) {
-      case "python":
-        print "processTraversal(\"\"\"" gensub("Bindings\\.of\\('id',([0-9]+)\\)", "\\1", "g") "\"\"\", jython, groovy)"
-        break
       default:
         print
         break
diff --git a/docs/preprocessor/awk/language-variants.awk b/docs/preprocessor/awk/language-variants.awk
index b2d0dbd..e849444 100644
--- a/docs/preprocessor/awk/language-variants.awk
+++ b/docs/preprocessor/awk/language-variants.awk
@@ -36,13 +36,6 @@
 
 { if (inCodeBlock) {
     switch (lang) {
-      case "python":
-        gsub(/^gremlin>/, ">>>")
-        gsub(/^==>/, "")
-        $0 = gensub(/processTraversal\("""(.*)""", jython, groovy)/, "\\1", 1)
-        $0 = gensub("g\\.V\\(([^\\)]+)", "g.V(Bindings\\.of('id',\\1)", "g")
-        print gensub("g\\.V\\(Bindings.of\\('id',(Bindings.of\\([^\\)]+\\))\\)\\)", "g.V(\\1)", "g")
-        break
       default:
         print
         break
diff --git a/docs/preprocessor/awk/prepare.awk b/docs/preprocessor/awk/prepare.awk
index 415a6b5..52a14cc 100644
--- a/docs/preprocessor/awk/prepare.awk
+++ b/docs/preprocessor/awk/prepare.awk
@@ -72,9 +72,6 @@
   split(b, l, ",")
   lang = l[1]
   switch (lang) {
-    case "python":
-      c = "#"
-      break
     default:
       c = "//"
       break
diff --git a/docs/preprocessor/awk/tabify.awk b/docs/preprocessor/awk/tabify.awk
index fc07331..fa22ed5 100644
--- a/docs/preprocessor/awk/tabify.awk
+++ b/docs/preprocessor/awk/tabify.awk
@@ -111,9 +111,6 @@
       }
       tabs[i] = lang
       switch (lang) {
-        case "python":
-          c = "#"
-          break
         default:
           c = "//"
           break
diff --git a/docs/preprocessor/install-plugins.sh b/docs/preprocessor/install-plugins.sh
index 5855e92..ba88213 100755
--- a/docs/preprocessor/install-plugins.sh
+++ b/docs/preprocessor/install-plugins.sh
@@ -52,9 +52,6 @@
   ((i++))
 done
 
-echo "installPlugin(new Artifact(\"org.apache.tinkerpop\", \"gremlin-python\", \"${TP_VERSION}\"))" >> ${INSTALL_FILE}
-echo "gremlin-python" >> ${TMP_DIR}/plugins.dir
-
 echo "System.exit(0)" >> ${INSTALL_FILE}
 echo -ne " * tinkerpop-sugar ... "
 
diff --git a/docs/preprocessor/preprocess-file.sh b/docs/preprocessor/preprocess-file.sh
index dbef22f..9ae43c2 100755
--- a/docs/preprocessor/preprocess-file.sh
+++ b/docs/preprocessor/preprocess-file.sh
@@ -133,7 +133,7 @@
   sed 's/\t/    /g' ${input} |
   awk -f ${AWK_SCRIPTS}/tabify.awk |
   awk -f ${AWK_SCRIPTS}/prepare.awk |
-  awk -f ${AWK_SCRIPTS}/init-code-blocks.awk -v TP_HOME="${TP_HOME}" -v PYTHONPATH="${TP_HOME}/gremlin-python/target/classes/Lib" |
+  awk -f ${AWK_SCRIPTS}/init-code-blocks.awk -v TP_HOME="${TP_HOME}" |
   awk -f ${AWK_SCRIPTS}/progressbar.awk -v tpl=${AWK_SCRIPTS}/progressbar.groovy.template |
   HADOOP_GREMLIN_LIBS="${CONSOLE_HOME}/ext/tinkergraph-gremlin/lib" bin/gremlin.sh | ${TP_HOME}/docs/preprocessor/control-characters.sh |
   ${lb} awk -f ${AWK_SCRIPTS}/ignore.awk   |
diff --git a/docs/site/home/downloads.html b/docs/site/home/downloads.html
index f89661b..db2f792 100644
--- a/docs/site/home/downloads.html
+++ b/docs/site/home/downloads.html
@@ -18,47 +18,47 @@
  <div class="row">
     <h3>Download Apache TinkerPop&trade;</h3>
     <p><img src="img/gremlin-download.png"  style="float:right;width:150px;padding:10px;"/>Apache TinkerPop provides three packaged downloads per release version. The
-       <a href="http://tinkerpop.apache.org/docs/current/reference/#gremlin-console">Gremlin Console</a> and <a href="http://tinkerpop.apache.org/docs/current/reference/#gremlin-server">Gremlin Server</a>
+       <a href="https://tinkerpop.apache.org/docs/current/reference/#gremlin-console">Gremlin Console</a> and <a href="https://tinkerpop.apache.org/docs/current/reference/#gremlin-server">Gremlin Server</a>
        downloads are binary distributions, which contain pre-packaged versions of these important TinkerPop applications that are designed to work out-of-the-box
        when unpackaged. The source distribution is a snapshot of the source code and files used in the building of those  binary distributions.</p>
     <h4>Current Releases</h4>
     <table class="table">
         <tr>
             <td>
-                <strong>3.4.2</strong> (latest, stable)
+                <strong>3.5.0</strong> (latest, stable)
             </td>
             <td>
-                28-May-2019
+                3-May-2021
             </td>
             <td>
-                <a href="https://github.com/apache/tinkerpop/blob/3.4.2/CHANGELOG.asciidoc#release-3-4-2">release notes</a> |
-                <a href="http://tinkerpop.apache.org/docs/3.4.2/upgrade/#_tinkerpop_3_4_2">upgrade</a> |
-                <a href="http://tinkerpop.apache.org/docs/3.4.2/">documentation</a> |
-                <a href="#" data-toggle="modal" data-target="#contributors-3_4_2">contributors</a>
+                <a href="https://github.com/apache/tinkerpop/blob/3.5.0/CHANGELOG.asciidoc#release-3-5-0">release notes</a> |
+                <a href="https://tinkerpop.apache.org/docs/3.5.0/upgrade/#_tinkerpop_3_5_0">upgrade</a> |
+                <a href="https://tinkerpop.apache.org/docs/3.5.0/">documentation</a> |
+                <a href="#" data-toggle="modal" data-target="#contributors-3_5_0">contributors</a>
             </td>
             <td align="right">
-                <a href="https://www.apache.org/dyn/closer.lua/tinkerpop/3.4.2/apache-tinkerpop-gremlin-console-3.4.2-bin.zip" class="btn btn-primary">Gremlin Console <span class="glyphicon glyphicon-download-alt"></span></a>
-                <a href="https://www.apache.org/dyn/closer.lua/tinkerpop/3.4.2/apache-tinkerpop-gremlin-server-3.4.2-bin.zip" class="btn btn-primary">Gremlin Server <span class="glyphicon glyphicon-download-alt"></span></a>
-                <a href="https://www.apache.org/dyn/closer.lua/tinkerpop/3.4.2/apache-tinkerpop-3.4.2-src.zip" class="btn btn-primary">Source <span class="glyphicon glyphicon-download-alt"></span></a>
+                <a href="https://www.apache.org/dyn/closer.lua/tinkerpop/3.5.0/apache-tinkerpop-gremlin-console-3.5.0-bin.zip" class="btn btn-primary">Gremlin Console <span class="glyphicon glyphicon-download-alt"></span></a>
+                <a href="https://www.apache.org/dyn/closer.lua/tinkerpop/3.5.0/apache-tinkerpop-gremlin-server-3.5.0-bin.zip" class="btn btn-primary">Gremlin Server <span class="glyphicon glyphicon-download-alt"></span></a>
+                <a href="https://www.apache.org/dyn/closer.lua/tinkerpop/3.5.0/apache-tinkerpop-3.5.0-src.zip" class="btn btn-primary">Source <span class="glyphicon glyphicon-download-alt"></span></a>
             </td>
         </tr>
         <tr>
             <td>
-                <strong>3.3.7</strong> (maintenance)
+                <strong>3.4.11</strong> (maintenance)
             </td>
             <td>
-                28-May-2019
+                3-May-2021
             </td>
             <td>
-                <a href="https://github.com/apache/tinkerpop/blob/3.3.7/CHANGELOG.asciidoc#release-3-3-7">release notes</a> |
-                <a href="http://tinkerpop.apache.org/docs/3.3.7/upgrade/#_tinkerpop_3_3_7">upgrade</a> |
-                <a href="http://tinkerpop.apache.org/docs/3.3.7/">documentation</a> |
-                <a href="#" data-toggle="modal" data-target="#contributors-3_3_7">contributors</a>
+                <a href="https://github.com/apache/tinkerpop/blob/3.4.11/CHANGELOG.asciidoc#release-3-4-11">release notes</a> |
+                <a href="https://tinkerpop.apache.org/docs/3.4.11/upgrade/#_tinkerpop_3_4_11">upgrade</a> |
+                <a href="https://tinkerpop.apache.org/docs/3.4.11/">documentation</a> |
+                <a href="#" data-toggle="modal" data-target="#contributors-3_4_11">contributors</a>
             </td>
             <td align="right">
-                <a href="https://www.apache.org/dyn/closer.lua/tinkerpop/3.3.7/apache-tinkerpop-gremlin-console-3.3.7-bin.zip" class="btn btn-primary">Gremlin Console <span class="glyphicon glyphicon-download-alt"></span></a>
-                <a href="https://www.apache.org/dyn/closer.lua/tinkerpop/3.3.7/apache-tinkerpop-gremlin-server-3.3.7-bin.zip" class="btn btn-primary">Gremlin Server <span class="glyphicon glyphicon-download-alt"></span></a>
-                <a href="https://www.apache.org/dyn/closer.lua/tinkerpop/3.3.7/apache-tinkerpop-3.3.7-src.zip" class="btn btn-primary">Source <span class="glyphicon glyphicon-download-alt"></span></a>
+                <a href="https://www.apache.org/dyn/closer.lua/tinkerpop/3.4.11/apache-tinkerpop-gremlin-console-3.4.11-bin.zip" class="btn btn-primary">Gremlin Console <span class="glyphicon glyphicon-download-alt"></span></a>
+                <a href="https://www.apache.org/dyn/closer.lua/tinkerpop/3.4.11/apache-tinkerpop-gremlin-server-3.4.11-bin.zip" class="btn btn-primary">Gremlin Server <span class="glyphicon glyphicon-download-alt"></span></a>
+                <a href="https://www.apache.org/dyn/closer.lua/tinkerpop/3.4.11/apache-tinkerpop-3.4.11-src.zip" class="btn btn-primary">Source <span class="glyphicon glyphicon-download-alt"></span></a>
             </td>
         </tr>
     </table>
@@ -67,8 +67,22 @@
     <div class="form-group row">
         <div class="col-xs-3">
     <select id="dropdownArchives" class="form-control">
-        <option selected="selected">3.4.1 (18-Mar-2019)</option>
+        <option selected="selected">3.4.10 (18-Jan-2021)</option>
+        <option>3.4.9 (7-Dec-2020)</option>
+        <option>3.4.8 (3-Aug-2020)</option>
+        <option>3.4.7 (1-Jun-2020)</option>
+        <option>3.4.6 (20-Feb-2020)</option>
+        <option>3.4.5 (3-Feb-2020)</option>
+        <option>3.4.4 (14-Oct-2019)</option>
+        <option>3.4.3 (5-Aug-2019)</option>
+        <option>3.4.2 (28-May-2019)</option>
+        <option>3.4.1 (18-Mar-2019)</option>
         <option>3.4.0 (2-Jan-2019)</option>
+        <option>3.3.11 (1-Jun-2020)</option>
+        <option>3.3.10 (3-Feb-2020)</option>
+        <option>3.3.9 (14-Oct-2019)</option>
+        <option>3.3.8 (5-Aug-2019)</option>
+        <option>3.3.7 (28-May-2019)</option>
         <option>3.3.6 (18-Mar-2019)</option>
         <option>3.3.5 (2-Jan-2019)</option>
         <option>3.3.4 (15-Oct-2018)</option>
@@ -111,21 +125,21 @@
              </td>
              <td id="archiveReleaseDate"></td>
              <td>
-                 <a id="archiveReleaseNotes" href="https://github.com/apache/tinkerpop/blob/3.4.1/CHANGELOG.asciidoc#release-3-4-1">release notes</a> |
-                 <span id="archiveUpgrade"><a href="http://tinkerpop.apache.org/docs/3.4.1/upgrade/#_tinkerpop_3_4_1">upgrade</a> |</span>
-                 <a id="archiveDocs" href="http://tinkerpop.apache.org/docs/3.4.1/">documentation</a> |
-                 <a id="archiveContributors" href="#" data-toggle="modal" data-target="#contributors-3_4_1">contributors</a>
+                 <a id="archiveReleaseNotes" href="https://github.com/apache/tinkerpop/blob/3.4.2/CHANGELOG.asciidoc#release-3-4-2">release notes</a> |
+                 <span id="archiveUpgrade"><a href="https://tinkerpop.apache.org/docs/3.4.2/upgrade/#_tinkerpop_3_4_2">upgrade</a> |</span>
+                 <a id="archiveDocs" href="https://tinkerpop.apache.org/docs/3.4.2/">documentation</a> |
+                 <a id="archiveContributors" href="#" data-toggle="modal" data-target="#contributors-3_4_2">contributors</a>
              </td>
              <td align="right">
-                 <a id="archiveDownloadConsole" href="https://archive.apache.org/dist/tinkerpop/3.4.1/apache-tinkerpop-gremlin-console-3.4.1-bin.zip" class="btn btn-primary">Gremlin Console <span class="glyphicon glyphicon-download-alt"></span></a>
-                 <a id="archiveDownloadServer" href="https://archive.apache.org/dist/tinkerpop/3.4.1/apache-tinkerpop-gremlin-server-3.4.1-bin.zip" class="btn btn-primary">Gremlin Server <span class="glyphicon glyphicon-download-alt"></span></a>
-                 <a id="archiveDownloadSource" href="https://archive.apache.org/dist/tinkerpop/3.4.1/apache-tinkerpop-3.4.1-src.zip" class="btn btn-primary">Source <span class="glyphicon glyphicon-download-alt"></span></a>
+                 <a id="archiveDownloadConsole" href="https://archive.apache.org/dist/tinkerpop/3.4.2/apache-tinkerpop-gremlin-console-3.4.2-bin.zip" class="btn btn-primary">Gremlin Console <span class="glyphicon glyphicon-download-alt"></span></a>
+                 <a id="archiveDownloadServer" href="https://archive.apache.org/dist/tinkerpop/3.4.2/apache-tinkerpop-gremlin-server-3.4.2-bin.zip" class="btn btn-primary">Gremlin Server <span class="glyphicon glyphicon-download-alt"></span></a>
+                 <a id="archiveDownloadSource" href="https://archive.apache.org/dist/tinkerpop/3.4.2/apache-tinkerpop-3.4.2-src.zip" class="btn btn-primary">Source <span class="glyphicon glyphicon-download-alt"></span></a>
              </td>
          </tr>
      </table>
     <p><strong>Note</strong> that upgrade documentation was only introduced at 3.1.1-incubating which is why there are no "upgrade" links in versions prior to that one.
     <p>As a convenience, TinkerPop also deploys packaged artifacts to the following locations:</p>
-    <p><a href="https://hub.docker.com/u/tinkerpop/">Docker</a> | <a href="http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.apache.tinkerpop%22">Maven Central</a> | <a href="https://pypi.python.org/pypi/gremlinpython/">PyPI</a> | <a href="https://www.npmjs.com/package/gremlin">npm</a> | <a href="https://www.nuget.org/packages/Gremlin.Net/">NuGet</a></p>
+    <p><a href="https://hub.docker.com/u/tinkerpop/">Docker</a> | <a href="https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.apache.tinkerpop%22">Maven Central</a> | <a href="https://pypi.python.org/pypi/gremlinpython/">PyPI</a> | <a href="https://www.npmjs.com/package/gremlin">npm</a> | <a href="https://www.nuget.org/packages/Gremlin.Net/">NuGet</a></p>
 
      <p><strong>Note</strong> this page lists official Apache releases only. TinkerPop occasionally produces unofficial binary release candidates (denoted by the suffix "-RC") which are NOT promoted or announced as actual release versions. <i>Such releases are for early development and evaluation purposes only.</i></p>
 
@@ -162,6 +176,306 @@
  </div>
 
     <!-- Contributor Modals -->
+    <!-- 3.5.0 -->
+    <div class="modal fade" id="contributors-3_5_0" tabindex="-1" role="dialog">
+        <div class="modal-dialog" role="document">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                    <h4 class="modal-title">3.5.0</h4>
+                </div>
+                <div class="modal-body">
+                    <p>Release Manager: Stephen Mallette</p>
+                    <pre><code>$ git shortlog -sn 3.4.11..3.5.0
+   769  Stephen Mallette
+    24  HadoopMarc
+    21  Florian Hockmann
+    19  Daniel Kuppitz
+    18  Divij Vaidya
+    14  Robert Dale
+    12  Lyndon Bauto
+    10  oyvindsabo
+     9  Jorge Bay Gondra
+     9  Kelvin Lawrence
+     2  Andrey Skorikov
+     2  Øyvind Sæbø
+     1  Andrey Artyukhov
+     1  Damien Stamates
+     1  Dan LaRocque
+     1  Dwitry
+     1  Ebrahim
+     1  Justin Chu
+     1  Liran Moysi
+     1  Nicolas Trangosi
+     1  Norio Akagi
+     1  jon-scho
+     1  ligniem
+     1  sandszhou.zj</code></pre>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <!-- 3.4.11 -->
+    <div class="modal fade" id="contributors-3_4_11" tabindex="-1" role="dialog">
+        <div class="modal-dialog" role="document">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                    <h4 class="modal-title">3.4.11</h4>
+                </div>
+                <div class="modal-body">
+                    <p>Release Manager: Stephen Mallette</p>
+                    <pre><code>$ git shortlog -sn 3.4.10..3.4.11
+    61  Stephen Mallette
+     3  Florian Hockmann
+     3  Radu Iviniciu
+     2  Clement de Groc
+     2  Ryan Quey
+     2  egetman
+     1  Florian Grieskamp
+     1  Justin Chu
+     1  Kelvin Lawrence
+     1  Norio Akagi
+     1  Serg Salo
+     1  Serhiy Salo
+     1  jan.jansen</code></pre>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <!-- 3.4.10 -->
+    <div class="modal fade" id="contributors-3_4_10" tabindex="-1" role="dialog">
+        <div class="modal-dialog" role="document">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                    <h4 class="modal-title">3.4.10</h4>
+                </div>
+                <div class="modal-body">
+                    <p>Release Manager: Stephen Mallette</p>
+                    <pre><code>$ git shortlog -sn 3.4.9..3.4.10
+    27  Stephen Mallette
+     1  Miltos
+     1  Simon
+     1  junshiguo</code></pre>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <!-- 3.4.9 -->
+    <div class="modal fade" id="contributors-3_4_9" tabindex="-1" role="dialog">
+        <div class="modal-dialog" role="document">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                    <h4 class="modal-title">3.4.9</h4>
+                </div>
+                <div class="modal-body">
+                    <p>Release Manager: Stephen Mallette</p>
+                    <pre><code>$ git shortlog -sn 3.4.8..3.4.9
+   114  Stephen Mallette
+    20  Divij Vaidya
+     4  Norio Akagi
+     3  Dave
+     3  Ian Robinson
+     3  Serg Salo
+     1  Bob Sutterfield
+     1  Gustavo Cavalieri Fernandes
+     1  Martin Häusler
+     1  Nicolas Trangosi
+     1  Oleksandr Porunov
+     1  deliliu
+     1  odidev</code></pre>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <!-- 3.4.8 -->
+    <div class="modal fade" id="contributors-3_4_8" tabindex="-1" role="dialog">
+        <div class="modal-dialog" role="document">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                    <h4 class="modal-title">3.4.8</h4>
+                </div>
+                <div class="modal-body">
+                    <p>Release Manager: Stephen Mallette</p>
+                    <pre><code>$ git shortlog -sn 3.4.7..3.4.8
+    21  Stephen Mallette
+     4  Mark Broadmore
+     3  Florian Hockmann
+     3  Jermy Li
+     1  Cholerae Hu
+     1  Divij Vaidya
+     1  Gustavo Cavalieri Fernandes</code></pre>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <!-- 3.4.7 -->
+    <div class="modal fade" id="contributors-3_4_7" tabindex="-1" role="dialog">
+        <div class="modal-dialog" role="document">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                    <h4 class="modal-title">3.4.7</h4>
+                </div>
+                <div class="modal-body">
+                    <p>Release Manager: Stephen Mallette</p>
+                    <pre><code>$ git shortlog -sn 3.4.6..3.4.7
+   106  Stephen Mallette
+    18  Liu Jianping
+    17  Florian Hockmann
+     4  Robert Dale
+     3  Jorge Bay Gondra
+     2  Daniel C. Weber
+     2  dzmitry.lahoda
+     1  Connor T. Skennerton
+     1  Eduard Tudenhoefner
+     1  Juha Haapsaari
+     1  Justin Chu
+     1  Nicolas Trangosi
+     1  olim7t</code></pre>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <!-- 3.4.6 -->
+    <div class="modal fade" id="contributors-3_4_6" tabindex="-1" role="dialog">
+        <div class="modal-dialog" role="document">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                    <h4 class="modal-title">3.4.6</h4>
+                </div>
+                <div class="modal-body">
+                    <p>Release Manager: Stephen Mallette</p>
+                    <pre><code>$ git shortlog -sn 3.4.5..3.4.6
+    10  Stephen Mallette
+     1  Nicolas Trangosi</code></pre>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <!-- 3.4.5 -->
+    <div class="modal fade" id="contributors-3_4_5" tabindex="-1" role="dialog">
+        <div class="modal-dialog" role="document">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                    <h4 class="modal-title">3.4.5</h4>
+                </div>
+                <div class="modal-body">
+                    <p>Release Manager: Stephen Mallette</p>
+                    <pre><code>$ git shortlog -sn 3.4.4..3.4.5
+   107  Stephen Mallette
+    17  Jorge Bay Gondra
+     9  Rusi Popov
+     8  Robert Dale
+     4  Jermy Li
+     3  thevalzo
+     2  Daniel Kuppitz
+     2  Norio Akagi
+     1  Cholerae Hu
+     1  root
+     1  wangshaogan
+     1  臻至</code></pre>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <!-- 3.4.4 -->
+    <div class="modal fade" id="contributors-3_4_4" tabindex="-1" role="dialog">
+        <div class="modal-dialog" role="document">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                    <h4 class="modal-title">3.4.4</h4>
+                </div>
+                <div class="modal-body">
+                    <p>Release Manager: Stephen Mallette</p>
+                    <pre><code>$ git shortlog -sn 3.4.3..3.4.4
+   157  Stephen Mallette
+     5  thirstycrow
+     3  Daniel Kuppitz
+     3  Jorge Bay Gondra
+     2  Justin Chu
+     2  Robert Dale
+     2  gion
+     2  sandszhou.zj
+     1  Ammarove
+     1  Dan LaRocque
+     1  Martin Kulhavy
+     1  sel-fish</code></pre>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <!-- 3.4.3 -->
+    <div class="modal fade" id="contributors-3_4_3" tabindex="-1" role="dialog">
+        <div class="modal-dialog" role="document">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                    <h4 class="modal-title">3.4.3</h4>
+                </div>
+                <div class="modal-body">
+                    <p>Release Manager: Stephen Mallette</p>
+                    <pre><code>$ git shortlog -sn 3.4.2..3.4.3
+   207  Stephen Mallette
+    13  Robert Dale
+    11  Divij Vaidya
+    11  jon-scho
+     8  Daniel Kuppitz
+     4  bryn
+     3  Eduard Tudenhoefner
+     2  sandszhou.zj
+     1  Dan LaRocque
+     1  xiyu.wxy</code></pre>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+                </div>
+            </div>
+        </div>
+    </div>
+
     <!-- 3.4.2 -->
     <div class="modal fade" id="contributors-3_4_2" tabindex="-1" role="dialog">
         <div class="modal-dialog" role="document">
@@ -172,7 +486,21 @@
                 </div>
                 <div class="modal-body">
                     <p>Release Manager: Stephen Mallette</p>
-                    <pre><code>$ git shortlog -sn 3.4.1..3.4.2</code></pre>
+                    <pre><code>$ git shortlog -sn 3.4.1..3.4.2
+   119  Stephen Mallette
+    20  Robert Dale
+     5  Eduard Tudenhoefner
+     4  Divij Vaidya
+     4  Jorge Bay Gondra
+     3  Daniel Kuppitz
+     3  Kevin Gallardo
+     2  Dwitry
+     1  Brett Peavler
+     1  Dan LaRocque
+     1  Daniel C. Weber
+     1  Florian Hockmann
+     1  Hieu Nguyen
+     1  sel-fish</code></pre>
                 </div>
                 <div class="modal-footer">
                     <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
@@ -259,6 +587,117 @@
         </div>
     </div>
 
+    <!-- 3.3.11 -->
+    <div class="modal fade" id="contributors-3_3_11" tabindex="-1" role="dialog">
+        <div class="modal-dialog" role="document">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                    <h4 class="modal-title">3.3.11</h4>
+                </div>
+                <div class="modal-body">
+                    <p>Release Manager: Stephen Mallette</p>
+                    <pre><code>$ git shortlog -sn 3.3.10..3.3.11
+    46  Stephen Mallette
+    13  Liu Jianping
+     7  Florian Hockmann
+     2  Daniel C. Weber
+     2  Jorge Bay Gondra
+     1  Justin Chu
+     1  Robert Dale
+     1  olim7t</code></pre>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <!-- 3.3.10 -->
+    <div class="modal fade" id="contributors-3_3_10" tabindex="-1" role="dialog">
+        <div class="modal-dialog" role="document">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                    <h4 class="modal-title">3.3.10</h4>
+                </div>
+                <div class="modal-body">
+                    <p>Release Manager: Stephen Mallette</p>
+                    <pre><code>$ git shortlog -sn 3.3.9..3.3.10
+    44  Stephen Mallette
+     9  Rusi Popov
+     8  Jorge Bay Gondra
+     4  Robert Dale
+     1  Cholerae Hu
+     1  Daniel Kuppitz
+     1  Norio Akagi
+     1  wangshaogan</code></pre>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <!-- 3.3.9 -->
+    <div class="modal fade" id="contributors-3_3_9" tabindex="-1" role="dialog">
+        <div class="modal-dialog" role="document">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                    <h4 class="modal-title">3.3.9</h4>
+                </div>
+                <div class="modal-body">
+                    <p>Release Manager: Stephen Mallette</p>
+                    <pre><code>$ git shortlog -sn 3.3.8..3.3.9
+    47  Stephen Mallette
+     4  thirstycrow
+     2  Jorge Bay Gondra
+     2  Justin Chu
+     2  gion
+     2  sandszhou.zj
+     1  Ammarove
+     1  Daniel Kuppitz
+     1  Martin Kulhavy
+     1  Robert Dale
+     1  sel-fish</code></pre>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <!-- 3.3.8 -->
+    <div class="modal fade" id="contributors-3_3_8" tabindex="-1" role="dialog">
+        <div class="modal-dialog" role="document">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                    <h4 class="modal-title">3.3.8</h4>
+                </div>
+                <div class="modal-body">
+                    <p>Release Manager: Stephen Mallette</p>
+                    <pre><code>$ git shortlog -sn 3.3.7..3.3.8
+    99  Stephen Mallette
+    11  Divij Vaidya
+     6  jon-scho
+     3  Daniel Kuppitz
+     2  Eduard Tudenhoefner
+     2  Robert Dale
+     1  sandszhou.zj
+     1  xiyu.wxy</code></pre>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+                </div>
+            </div>
+        </div>
+    </div>
+
     <!-- 3.3.7 -->
     <div class="modal fade" id="contributors-3_3_7" tabindex="-1" role="dialog">
         <div class="modal-dialog" role="document">
@@ -269,7 +708,15 @@
                 </div>
                 <div class="modal-body">
                     <p>Release Manager: Stephen Mallette</p>
-                    <pre><code>$ git shortlog -sn 3.3.6..3.3.7</code></pre>
+                    <pre><code>$ git shortlog -sn 3.3.6..3.3.7
+    46  Stephen Mallette
+     9  Robert Dale
+     4  Eduard Tudenhoefner
+     2  Daniel Kuppitz
+     2  Dwitry
+     2  Jorge Bay Gondra
+     1  Hieu Nguyen
+     1  Kevin Gallardo</code></pre>
                 </div>
                 <div class="modal-footer">
                     <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
@@ -1275,7 +1722,7 @@
             $("#archiveVersion").html(version);
             $("#archiveReleaseDate").html(releaseDate);
             $("#archiveReleaseNotes").attr("href", "https://github.com/apache/tinkerpop/blob/master/CHANGELOG.asciidoc#release-" + versionHyphened);
-            $("#archiveDocs").attr("href", "http://tinkerpop.apache.org/docs/" + version);
+            $("#archiveDocs").attr("href", "https://tinkerpop.apache.org/docs/" + version);
             $("#archiveContributors").attr("data-target", "#contributors-" + versionUnderscored);
 
             var versionsWithOldNaming = ["3.2.1", "3.1.3", "3.2.0-incubating", "3.1.2-incubating", "3.1.1-incubating",
@@ -1299,7 +1746,7 @@
                 $("#archiveUpgrade a").attr("href", "#");
                 $("#archiveUpgrade").hide();
             } else {
-                $("#archiveUpgrade a").attr("href", "http://tinkerpop.apache.org/docs/" + version + "/upgrade/#_tinkerpop_" + versionUnderscored);
+                $("#archiveUpgrade a").attr("href", "https://tinkerpop.apache.org/docs/" + version + "/upgrade/#_tinkerpop_" + versionUnderscored);
                 $("#archiveUpgrade").show();
             }
 
diff --git a/docs/site/home/gremlin.html b/docs/site/home/gremlin.html
index a8a6cd3..5fb5c2b 100644
--- a/docs/site/home/gremlin.html
+++ b/docs/site/home/gremlin.html
@@ -26,7 +26,7 @@
  <div class="container">
     <div class="row">
        <div class="col-sm-10 col-md-10">
-          <a href="http://arxiv.org/abs/1508.03843">Gremlin</a> is the graph traversal language of <a href="http://tinkerpop.apache.org/">Apache TinkerPop</a>.
+          <a href="http://arxiv.org/abs/1508.03843">Gremlin</a> is the graph traversal language of <a href="https://tinkerpop.apache.org/">Apache TinkerPop</a>.
           Gremlin is a <a href="https://en.wikipedia.org/wiki/Functional_programming">functional</a>, <a href="https://en.wikipedia.org/wiki/Dataflow_programming">data-flow</a>
           language that enables users to succinctly express complex traversals on (or queries of) their application's property graph. Every Gremlin traversal is composed of a sequence of (potentially nested) steps. A step
           performs an atomic operation on the data stream. Every step is either a <em>map</em>-step (transforming the objects in the stream), a <em>filter</em>-step (removing objects
@@ -250,14 +250,14 @@
        </div>
        <div class="col-sm-7 col-md-8">
           A declarative Gremlin traversal does not tell the traversers the order in which to execute their walk, but instead, allows each traverser to select a pattern to execute from a collection
-          of (potentially nested) patterns. The <a href="http://tinkerpop.apache.org/docs/current/reference/#match-step">declarative traversal</a> on the left yields the same result as the imperative traversal above. However, the declarative traversal has the added benefit
+          of (potentially nested) patterns. The <a href="https://tinkerpop.apache.org/docs/current/reference/#match-step">declarative traversal</a> on the left yields the same result as the imperative traversal above. However, the declarative traversal has the added benefit
           that it leverages not only a compile-time query planner (like imperative traversals), but also a runtime query planner that chooses which traversal pattern to execute next based on the
           historic statistics of each pattern -- favoring those patterns which tend to reduce/filter the most data.
        </div>
     </div>
     <br/>
     The user can write their traversals in any way they choose. However, ultimately when their traversal is compiled, and depending on the underlying execution engine
-    (i.e. an OLTP graph database or an OLAP graph processor), the user's traversal is rewritten by a set of <em><a href="http://tinkerpop.apache.org/docs/current/reference/#traversalstrategy">traversal strategies</a></em> which do their best to determine the most optimal execution
+    (i.e. an OLTP graph database or an OLAP graph processor), the user's traversal is rewritten by a set of <em><a href="https://tinkerpop.apache.org/docs/current/reference/#traversalstrategy">traversal strategies</a></em> which do their best to determine the most optimal execution
     plan based on an understanding of graph data access costs as well as the underlying data systems's unique capabilities (e.g. fetch the Gremlin vertex from the graph database's "name"-index).
     Gremlin has been designed to give users flexibility in how they express their queries and graph system providers flexibility in how to efficiently evaluate traversals against their TinkerPop-enabled data system.
  </div>
@@ -277,7 +277,7 @@
           "programming languages" are not as great as we are taught to believe. Gremlin unifies this divide because traversals can be written in any
           programming language that supports function <a href="https://en.wikipedia.org/wiki/Function_composition">composition</a> and <a href="https://en.wikipedia.org/wiki/Nested_function">nesting</a> (which every major programming language supports). In this way, the user's
           Gremlin traversals are written along side their application code and benefit from the advantages afforded by the host language and its tooling
-          (e.g. type checking, syntax highlighting, dot completion, etc.). Various <a href="http://tinkerpop.apache.org/docs/current/tutorials/gremlin-language-variants/">Gremlin language variants</a> exist including: Gremlin-Java, Gremlin-Groovy, <a href="http://tinkerpop.apache.org/docs/current/reference/#gremlin-python">Gremlin-Python</a>,
+          (e.g. type checking, syntax highlighting, dot completion, etc.). Various <a href="https://tinkerpop.apache.org/docs/current/reference/#gremlin-drivers-variants">Gremlin language variants</a> exist including: Gremlin-Java, Gremlin-Groovy, <a href="https://tinkerpop.apache.org/docs/current/reference/#gremlin-python">Gremlin-Python</a>,
           <a href="https://github.com/mpollmeier/gremlin-scala">Gremlin-Scala</a>, etc.
        </div>
        <div class="col-md-12">
diff --git a/docs/site/home/img/logos/hugegraph-logo.png b/docs/site/home/img/logos/hugegraph-logo.png
new file mode 100644
index 0000000..41fdf39
--- /dev/null
+++ b/docs/site/home/img/logos/hugegraph-logo.png
Binary files differ
diff --git a/docs/site/home/index.html b/docs/site/home/index.html
index c17c728..5415f41 100644
--- a/docs/site/home/index.html
+++ b/docs/site/home/index.html
@@ -26,23 +26,23 @@
             <br/>
             <p>
             </p>
-            <b><font size="4">TinkerPop</font> <font size="4">3.4.2</font></b> (<font size="2">Released: 28-May-2019</font>)
+            <b><font size="4">TinkerPop</font> <font size="4">3.5.0</font></b> (<font size="2">Released: 3-May-2021</font>)
             <p><b>Downloads</b></p>
             <p>
-               <a href="https://www.apache.org/dyn/closer.lua/tinkerpop/3.4.2/apache-tinkerpop-gremlin-console-3.4.2-bin.zip" class="btn btn-primary">Gremlin Console <span class="glyphicon glyphicon-download-alt"></span></a>
-               <a href="https://www.apache.org/dyn/closer.lua/tinkerpop/3.4.2/apache-tinkerpop-gremlin-server-3.4.2-bin.zip" class="btn btn-primary">Gremlin Server <span class="glyphicon glyphicon-download-alt"></span></a>
-               <a href="https://www.apache.org/dyn/closer.lua/tinkerpop/3.4.2/apache-tinkerpop-3.4.2-src.zip" class="btn btn-primary">Source <span class="glyphicon glyphicon-download-alt"></span></a>
+               <a href="https://www.apache.org/dyn/closer.lua/tinkerpop/3.5.0/apache-tinkerpop-gremlin-console-3.5.0-bin.zip" class="btn btn-primary">Gremlin Console <span class="glyphicon glyphicon-download-alt"></span></a>
+               <a href="https://www.apache.org/dyn/closer.lua/tinkerpop/3.5.0/apache-tinkerpop-gremlin-server-3.5.0-bin.zip" class="btn btn-primary">Gremlin Server <span class="glyphicon glyphicon-download-alt"></span></a>
+               <a href="https://www.apache.org/dyn/closer.lua/tinkerpop/3.5.0/apache-tinkerpop-3.5.0-src.zip" class="btn btn-primary">Source <span class="glyphicon glyphicon-download-alt"></span></a>
             </p>
             <div class="row">
                <div class="col-md-6">
                   <p><b>Documentation</b></p>
                   <ul>
-                     <li><a href="http://tinkerpop.apache.org/docs/current/">TinkerPop Documentation</a></li>
+                     <li><a href="https://tinkerpop.apache.org/docs/current/">TinkerPop Documentation</a></li>
                      <ul>
-                        <li><a href="http://tinkerpop.apache.org/docs/current/reference">Reference Documentation</a></li>
+                        <li><a href="https://tinkerpop.apache.org/docs/current/reference">Reference Documentation</a></li>
                      </ul>
-                     <li><a href="http://tinkerpop.apache.org/docs/3.4.2/upgrade/#_tinkerpop_3_4_2">Upgrade Information</a></li>
-                     <li>TinkerPop Javadoc - <a href="http://tinkerpop.apache.org/javadocs/current/core/">core</a> / <a href="http://tinkerpop.apache.org/javadocs/current/full/">full</a></li>
+                     <li><a href="https://tinkerpop.apache.org/docs/3.5.0/upgrade/#_tinkerpop_3_5_0">Upgrade Information</a></li>
+                     <li>TinkerPop Javadoc - <a href="https://tinkerpop.apache.org/javadocs/current/core/">core</a> / <a href="https://tinkerpop.apache.org/javadocs/current/full/">full</a></li>
                   </ul>
                </div>
                <div class="col-md-6">
@@ -95,19 +95,19 @@
          <div class="item">
                   <pre><code class="language-gremlin">
     // What are the names of projects that were created by two friends?
-    g.V().match(
-      as("a").out("knows").as("b"),
-      as("a").out("created").as("c"),
-      as("b").out("created").as("c"),
-      as("c").in("created").count().is(2)).
-        select("c").by("name")
+    g.V().
+      match(as("a").out("knows").as("b"),
+            as("a").out("created").as("c"),
+            as("b").out("created").as("c"),
+            as("c").in("created").count().is(2)).
+      select("c").by("name")
           </code></pre>
          </div>
          <div class="item">
                   <pre><code class="language-gremlin">
 
-    // What are the names of the managers in
-    //  the management chain going from Gremlin to the CEO?
+    // What are the names of the managers in the
+    // management chain going from Gremlin to the CEO?
     g.V().has("name","gremlin").
       repeat(in("manages")).until(has("title","ceo")).
       path().by("name")
@@ -120,7 +120,7 @@
     // What is the distribution of job titles amongst Gremlin's collaborators?
     g.V().has("name","gremlin").as("a").
       out("created").in("created").
-        where(neq("a")).
+      where(neq("a")).
       groupCount().by("title")
 
           </code></pre>
@@ -131,9 +131,9 @@
     // Get a ranking of the most relevant products for Gremlin given his purchase history.
     g.V().has("name","gremlin").out("bought").aggregate("stash").
       in("bought").out("bought").
-        where(not(within("stash"))).
+      where(not(within("stash"))).
       groupCount().
-        order(local).by(values,desc)
+      order(local).by(values,desc)
           </code></pre>
          </div>
       </div>
@@ -144,12 +144,12 @@
       <p><img src="img/graph-globe.png" style="float:left;width:15%;padding:10px;"> A <strong>graph</strong> is a structure composed of <strong>vertices</strong> and <strong>edges</strong>.
          Both vertices and edges can have an arbitrary number of key/value-pairs called <strong>properties</strong>.
          Vertices denote discrete objects such as a person, a place, or an event. Edges denote relationships between vertices. For instance, a person may know
-         another person, have been involved in an event, and/or was recently at a particular place. Properties express non-relational information about the
-         vertices and edges. Example properties include a vertex having a name, an age and an edge having a timestamp and/or a weight. Together, the aforementioned
+         another person, have been involved in an event, and/or have recently been at a particular place. Properties express non-relational information about the
+         vertices and edges. Example properties include a vertex having a name and an age, and an edge having a timestamp and/or a weight. Together, the aforementioned
          graph is known as a <strong>property graph</strong> and it is the foundational data structure of Apache TinkerPop.
       </p>
       <br/>
-      <p><img src="img/graph-vs-table.png" style="float:right;width:22%;padding:10px;">If a user's domain is composed of a heterogenous set of objects (vertices) that can be related to one another in a multitude of ways (edges),
+      <p><img src="img/graph-vs-table.png" style="float:right;width:22%;padding:10px;">If a user's domain is composed of a heterogeneous set of objects (vertices) that can be related to one another in a multitude of ways (edges),
          then a graph may be the right representation to use. In a graph, each vertex is seen as an atomic entity (not simply a "row in a table") that
          can be linked to any other vertex or have properties added or removed at will. This empowers the data modeler to think in terms of actors within
          a world of complex relations as opposed to, in relational databases, statically-typed tables joined in aggregate. Once a domain is modeled, that
@@ -159,7 +159,7 @@
          effectively leverage that structure.
       </p>
       <br/>
-      <p><a href="#"><img src="img/apache-tinkerpop-logo.png" style="float:left;width:22%;padding:10px;"/></a>Apache TinkerPop&trade; is an open source, vendor-agnostic, graph computing framework distributed under the commercial friendly <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache2 license</a>.
+      <p><a href="#"><img src="img/apache-tinkerpop-logo.png" style="float:left;width:22%;padding:10px;"/></a>Apache TinkerPop&trade; is an open source, vendor-agnostic, graph computing framework distributed under the commercial friendly <a href="https://www.apache.org/licenses/LICENSE-2.0">Apache2 license</a>.
          When a data system is <a href="providers.html">TinkerPop-enabled</a>, its users are able to model their domain as a graph and analyze that graph using the <a href="gremlin.html">Gremlin graph traversal language</a>.
          Furthermore, all TinkerPop-enabled systems integrate with one another allowing them to easily expand their offerings as well as allowing users to choose the appropriate graph
          technology for their application. Sometimes an application is best served by an in-memory, transactional graph database. Sometimes a multi-machine distributed graph database will do the job.
@@ -172,11 +172,11 @@
       <div class="col-xs-12">
          <div class="row">
             <div class="col-xs-8">
-               TinkerPop is an open source project that <a href="http://tinkerpop.apache.org/docs/current/dev/developer#_contributing">welcomes contributions</a>. There are many ways to get involved:
+               TinkerPop is an open source project that <a href="https://tinkerpop.apache.org/docs/current/dev/developer#_contributing">welcomes contributions</a>. There are many ways to get involved:
                <p/>
                <ol>
                   <li>
-                     Join the <a href="http://groups.google.com/group/gremlin-users">Gremlin-Users</a> public mailing list.
+                     Join the <a href="https://groups.google.com/group/gremlin-users">Gremlin-Users</a> public mailing list.
                      <ul>
                         <li>Help users by answering questions and demonstrating your expertise in TinkerPop and graphs.</li>
                      </ul>
@@ -199,17 +199,17 @@
                      <li>Become a TinkerPop Committer and help determine the evolution of The TinkerPop.</li>
                   </ul>
                </ol>
-               <p>To build TinkerPop from source, please review the <a href="http://tinkerpop.apache.org/docs/current/dev/developer/#building-testing">developer documentation</a>.
+               <p>To build TinkerPop from source, please review the <a href="https://tinkerpop.apache.org/docs/current/dev/developer/#building-testing">developer documentation</a>.
             </div>
             <div class="col-xs-4">
-               <a href="http://tinkerpop.apache.org/docs/current/dev/developer/"><img src="img/gremlin-apache.png" width="250" class="img-responsive" /></a>
+               <a href="https://tinkerpop.apache.org/docs/current/dev/developer/"><img src="img/gremlin-apache.png" width="250" class="img-responsive" /></a>
             </div>
          </div>
          <h3>Community Contributions</h3>
          TinkerPop is at the center of a larger development ecosystem that extends on its core interfaces, integration points, and ideas.  The graph systems and libraries below represent both
-         TinkerPop-maintained reference implementations as well as third-party managed projects. The TinkerPop community is always interested in hearing about projects like these and aiding
+         TinkerPop-maintained reference implementations and third-party managed projects. The TinkerPop community is always interested in hearing about projects like these and aiding
          in their support. Please read our <a href="policy.html">provider listing policy</a> and feel free to promote such projects on the user and developer mailing lists. Information on
-         how to build implementations of the various interfaces that TinkerPop exposes can be found in the <a href="http://tinkerpop.apache.org/docs/current/dev/provider/">Provider Documentation</a>.
+         how to build implementations of the various interfaces that TinkerPop exposes can be found in the <a href="https://tinkerpop.apache.org/docs/current/dev/provider/">Provider Documentation</a>.
          <p/>
          <a name="graph-systems"></a>
          <h4 id="graph-systems">Graph Systems</h4>
@@ -221,23 +221,25 @@
             <li><a href="https://github.com/lambdazen/bitsy/wiki">Bitsy</a> - A small, fast, embeddable, durable in-memory graph database.</li>
             <li><a href="https://github.com/blazegraph/tinkerpop3">Blazegraph</a> - RDF graph database with OLTP support.</li>
             <li><a href="https://docs.microsoft.com/en-us/azure/cosmos-db/graph-introduction">CosmosDB</a> - Microsoft's distributed OLTP graph database.</li>
-            <li><a href="https://github.com/MartinHaeusler/chronos/tree/master/org.chronos.chronograph">ChronoGraph</a> - A versioned graph database.</li>
-            <li><a href="http://www.datastax.com/products/datastax-enterprise-graph">DSEGraph</a> - DataStax graph database with OLTP and OLAP support.</li>
+            <li><a href="https://github.com/Txture/chronos/tree/master/org.chronos.chronograph">ChronoGraph</a> - A versioned graph database.</li>
+            <li><a href="https://www.datastax.com/products/datastax-enterprise-graph">DSEGraph</a> - DataStax graph database with OLTP and OLAP support.</li>
             <li><a href="https://grakn.ai/">GRAKN.AI</a> - Distributed OLTP/OLAP knowledge graph system.</li>
-            <li><a href="http://tinkerpop.apache.org/docs/current/reference/#sparkgraphcomputer">Hadoop (Spark)</a> - OLAP graph processor using Spark.</li>
+            <li><a href="https://tinkerpop.apache.org/docs/current/reference/#sparkgraphcomputer">Hadoop (Spark)</a> - OLAP graph processor using Spark.</li>
             <li><a href="https://github.com/rayokota/hgraphdb">HGraphDB</a> - OLTP graph database running on Apache HBase.</li>
             <li><a href="https://www.huaweicloud.com/en-us/product/ges.html">Huawei Graph Engine Service</a> - Fully-managed, distributed, at-scale graph query and analysis service that provides a visualized interactive analytics platform.</li>
+            <li><a href="https://github.com/hugegraph/hugegraph">HugeGraph</a> - A high-speed, distributed and scalable OLTP and OLAP graph database with visualized analytics platform.</li>
             <li><a href="https://console.ng.bluemix.net/catalog/services/ibm-graph/">IBM Graph</a> - OLTP graph database as a service.</li>
             <li><a href="http://janusgraph.org/">JanusGraph</a> - Distributed OLTP and OLAP graph database with BerkeleyDB, Apache Cassandra and Apache HBase support.</li>
             <li><a href="https://github.com/awslabs/dynamodb-janusgraph-storage-backend//">JanusGraph (Amazon)</a> - The Amazon DynamoDB Storage Backend for JanusGraph.</li>
-            <li><a href="http://tinkerpop.apache.org/docs/current/reference/#neo4j-gremlin">Neo4j</a> - OLTP graph database (embedded and high availability).</li>
+            <li><a href="https://tinkerpop.apache.org/docs/current/reference/#neo4j-gremlin">Neo4j</a> - OLTP graph database (embedded and high availability).</li>
             <li><a href="https://github.com/SteelBridgeLabs/neo4j-gremlin-bolt">neo4j-gremlin-bolt</a> - OLTP graph database (using Bolt Protocol).</li>
             <li><a href="https://github.com/orientechnologies/orientdb-gremlin">OrientDB</a> - OLTP graph database</li>
-            <li><a href="http://s2graph.apache.org/">Apache S2Graph</a> - OLTP graph database running on Apache HBase.</li>
+            <li><a href="https://github.com/ShiftLeftSecurity/overflowdb">OverflowDB</a> - In-memory graph database with low memory footprint</li>
+            <li><a href="https://s2graph.apache.org/">Apache S2Graph</a> - OLTP graph database running on Apache HBase.</li>
             <li><a href="https://github.com/pietermartin/sqlg">Sqlg</a> - OLTP implementation on SQL databases.</li>
-            <li><a href="http://stardog.com/">Stardog</a> - RDF graph database with OLTP and OLAP support.</li>
-            <li><a href="http://tinkerpop.apache.org/docs/current/reference/#tinkergraph-gremlin">TinkerGraph</a> - In-memory OLTP and OLAP reference implementation.</li>
-            <li><a href="http://thinkaurelius.github.io/titan/">Titan</a> - Distributed OLTP and OLAP graph database with BerkeleyDB, Apache Cassandra and Apache HBase support.</li>
+            <li><a href="https://stardog.com/">Stardog</a> - RDF graph database with OLTP and OLAP support.</li>
+            <li><a href="https://tinkerpop.apache.org/docs/current/reference/#tinkergraph-gremlin">TinkerGraph</a> - In-memory OLTP and OLAP reference implementation.</li>
+            <li><a href="https://thinkaurelius.github.io/titan/">Titan</a> - Distributed OLTP and OLAP graph database with BerkeleyDB, Apache Cassandra and Apache HBase support.</li>
             <li><a href="https://github.com/awslabs/dynamodb-titan-storage-backend">Titan (Amazon)</a> - The Amazon DynamoDB storage backend for Titan.</li>
             <li><a href="https://github.com/classmethod/tupl-titan-storage-backend">Titan (Tupl)</a> - The Tupl storage backend for Titan.</li>
             <li><a href="https://github.com/rmagen/unipop">Unipop</a> - OLTP Elasticsearch and JDBC backed graph.</li>
@@ -246,22 +248,24 @@
          <h4 id="language-variants-compilers">Query Languages</h4>
          <small>[<a href="providers.html#query-language-providers">learn more</a>]</small>
          <ul>
-            <li><a href="https://github.com/opencypher/cypher-for-gremlin">cypher-for-gremlin</a> - A Cypher to Gremlin traversal transpiler.</li>
+            <li><a href="https://github.com/opencypher/cypher-for-gremlin">cypher-for-gremlin</a> - A Cypher-to-Gremlin traversal transpiler.</li>
             <li><a href="http://syncleus.com/Ferma/">Ferma</a> (java/dsl) - An ORM / OGM for Apache TinkerPop.</li>
             <li><a href="https://github.com/davebshow/goblin">Goblin</a> (python/dsl) - Goblin OGM for the TinkerPop 3 Gremlin Server.</li>
-            <li><a href="http://tinkerpop.apache.org/docs/current/reference/#gremlin-DotNet">Gremlin.Net</a> (.NET - C#/variant) - Gremlin hosted in C# for use with any .NET-based VM.</li>
-            <li><a href="http://tinkerpop.apache.org/docs/current/reference/#gremlin-javascript">gremlin-javascript</a> (js) - Gremlin hosted in JavaScript for use with Node.js.</li>
+            <li><a href="https://tinkerpop.apache.org/docs/current/reference/#gremlin-DotNet">Gremlin.Net</a> (.NET - C#/variant) - Gremlin hosted in C# for use with any .NET-based VM.</li>
+            <li><a href="https://tinkerpop.apache.org/docs/current/reference/#gremlin-javascript">gremlin-javascript</a> (js) - Gremlin hosted in JavaScript for use with Node.js.</li>
             <li><a href="https://github.com/gremlin-orm/gremlin-orm">gremlin-orm</a> (javascript) Gremlin ORM for Node.js.</li>
-            <li><a href="http://tinkerpop.apache.org/docs/current/reference/#gremlin-python">gremlin-python</a> (python/variant) - Gremlin hosted in Python for use with any Python-based VM.</li>
+            <li><a href="https://tinkerpop.apache.org/docs/current/reference/#gremlin-python">gremlin-python</a> (python/variant) - Gremlin hosted in Python for use with any Python-based VM.</li>
             <li><a href="https://github.com/emehrkay/gremlinpy">gremlin-py</a> (python/variant) - Write pure Python Gremlin that can be sent to Gremlin Server.</li>
+            <li><a href="https://github.com/wolf4ood/gremlin-rs">gremlin-rs</a> (rust/variant) - A Gremlin Server driver and language variant for Rust.</li>
             <li><a href="https://github.com/mpollmeier/gremlin-scala">gremlin-scala</a> (scala/variant) - A Scala-based Gremlin language variant for TinkerPop3.</li>
             <li><a href="https://github.com/karthicks/gremlin-ogm">gremlin-objects</a> (java/dsl) - An Object Graph Mapping Library For Gremlin.</li>
             <li><a href="https://github.com/jbmusso/gremlin-template-string">gremlin-template-string</a> (js/variant) - A Gremlin language builder.</li>
+            <li><a href="https://github.com/debug-ito/greskell">greskell</a> (haskell/variant) - Haskell binding for Gremlin graph query language.</li>
             <li><a href="https://github.com/davebshow/ipython-gremlin">ipython-gremlin</a> (python/variant) - Gremlin in IPython and Jupyter.</li>
             <li><a href="https://github.com/pm-dev/kotlin-gremlin-ogm">kotlin-gremlin-ogm</a> (kotlin/dsl) - An Object Graph Mapping Library for Kotlin and Gremlin.</li>
             <li><a href="http://ogre.clojurewerkz.org/">ogre</a> (clojure/variant) - A Clojure language wrapper for TinkerPop3.</li>
-            <li><a href="http://bayofmany.github.io/">Peapod</a> (java/dsl) - An object-graph-wrapper.</li>
-            <li><a href="http://tinkerpop.apache.org/docs/current/reference/#sparql-gremlin">sparql-gremlin</a> (sparql/distinct) - A SPARQL to Gremlin traversal compiler.</li>
+            <li><a href="https://bayofmany.github.io/">Peapod</a> (java/dsl) - An object-graph-wrapper.</li>
+            <li><a href="https://tinkerpop.apache.org/docs/current/reference/#sparql-gremlin">sparql-gremlin</a> (sparql/distinct) - A SPARQL to Gremlin traversal compiler.</li>
             <li><a href="https://github.com/Microsoft/spring-data-gremlin">spring-data-gremlin</a> (java/dsl) - Spring Data support for TinkerPop-enabled graph systems.</li>
             <li><a href="https://github.com/twilmes/sql-gremlin">sql-gremlin</a> (sql/distinct) - An SQL to Gremlin traversal compiler.</li>
          </ul>
@@ -270,13 +274,14 @@
          <ul>
             <li><a href="https://github.com/davebshow/gremlinclient">gremlinclient</a> (python) - An asynchronous Python 2/3 client for Gremlin Server that allows for flexible coroutine syntax - Trollius, Tornado, Asyncio.</li>
             <li><a href="https://github.com/marcelocf/gremlin_client">gremlin_client</a> (ruby) - A Gremlin Server driver for Ruby.</li>
-            <li><a href="http://tinkerpop.apache.org/docs/current/reference/#connecting-via-java">gremlin-driver</a> (java) - A Gremlin Server driver for Java.</li>
+            <li><a href="https://tinkerpop.apache.org/docs/current/reference/#connecting-via-java">gremlin-driver</a> (java) - A Gremlin Server driver for Java.</li>
+            <li><a href="https://github.com/northwesternmutual/grammes">grammes</a> (go) - A strongly typed Gremlin server driver for Go.</li>
             <li><a href="https://github.com/qasaur/gremgo">gremgo</a> (go) - A Gremlin Server driver for Go.</li>
             <li><a href="https://github.com/Revmaker/gremlex">gremlex</a> (elixir) - A Gremlin Server driver for Elixir.</li>
-            <li><a href="http://tinkerpop.apache.org/docs/current/reference/#gremlin-DotNet">Gremlin.Net</a> (.NET - C#) - Gremlin Server driver for .NET.</li>
+            <li><a href="https://tinkerpop.apache.org/docs/current/reference/#gremlin-DotNet">Gremlin.Net</a> (.NET - C#) - Gremlin Server driver for .NET.</li>
             <li><a href="https://github.com/PommeVerte/gremlin-php">gremlin-php</a> (php) - A Gremlin Server driver for PHP.</li>
-            <li><a href="http://tinkerpop.apache.org/docs/current/reference/#gremlin-python">gremlin-python</a> (python) - Gremlin Server driver for Python.</li>
-            <li><a href="http://gremlinrestclient.readthedocs.org/en/latest/">gremlinrestclient</a> (python) - Python 2/3 library that uses HTTP to communicate with the Gremlin Server over REST.</li>
+            <li><a href="https://tinkerpop.apache.org/docs/current/reference/#gremlin-python">gremlin-python</a> (python) - Gremlin Server driver for Python.</li>
+            <li><a href="https://gremlinrestclient.readthedocs.org/en/latest/">gremlinrestclient</a> (python) - Python 2/3 library that uses HTTP to communicate with the Gremlin Server over REST.</li>
             <li><a href="https://github.com/ExRam/ExRam.Gremlinq">Gremlinq</a> (.NET) - A strongly typed server driver.</li>
             <li><a href="https://github.com/windj007/python-gremlin-rest">python-gremlin-rest</a> (python) - A REST-based client for Gremlin Server.</li>
             <li><a href="https://github.com/coreyauger/reactive-gremlin">reactive-gremlin</a> (scala) - An Akka HTTP Websocket Connector.</li>
@@ -289,12 +294,14 @@
             <li><a href="https://www.exakat.io/">exakat.io</a> - Static analysis engine for PHP, powered by Gremlin.</li>
             <li><a href="https://bricaud.github.io/graphexp/graphexp.html">Graphexp</a> - Interactive visualization of the Gremlin graph database with D3.js.</li>
             <li><a href="https://github.com/bechbd/gremlin-ide">gremlin-ide</a> - An IDE for Apache TinkerPop-enabled databases using React and Electron.</li>
-            <li><a href="http://cambridge-intelligence.com/keylines/">KeyLines</a> - A JavaScript SDK for building powerful, custom and scalable graph visualization applications.</li>
+            <li><a href="https://gremlify.com/">gremlify</a> - A Gremlin workspace for queries and visualization.</li>
+            <li><a href="https://github.com/prabushitha/gremlin-visualizer">Gremlin-Visualizer</a> A visualization tool for the results of gremlin traversals.</li>
+            <li><a href="https://cambridge-intelligence.com/keylines/">KeyLines</a> - A JavaScript SDK for building powerful, custom and scalable graph visualization applications.</li>
             <li><a href="https://github.com/meltwater/jugri">JUGRI</a> - A Jupyter Gremlin interface.</li>
-            <li><a href="http://linkurio.us/">Linkurious</a> - A browser-based graph visualization software to search, explore and visualize connected data.</li>
-            <li><a href="http://www.pitneybowes.com/us/customer-information-management/data-integration-management/spectrum-data-hub-module.html">Pitney Bowes Spectrum Data Hub Module</a> - Uses Gremlin OLTP to query Neo4j-powered master data management based graph database.</li>
+            <li><a href="https://linkurio.us/">Linkurious</a> - A browser-based graph visualization software to search, explore and visualize connected data.</li>
+            <li><a href="https://customer.precisely.com/s/article/Spectrum-Technology-Platform-Data-Hub-Module">Precisely Spectrum Data Hub Module</a> - Uses Gremlin OLTP to query Neo4j-powered master data management based graph database.</li>
             <li><a href="https://www.stackstate.com/">StackState</a> - Monitoring and AIOps allowing users to utilize Gremlin for analytical functions.</li>
-            <li><a href="http://tomsawyer.com/products/perspectives/">Tom Sawyer Perspectives</a> - Advanced graphics-based software for building enterprise-class data relationship visualization and analysis applications.</li>
+            <li><a href="https://www.tomsawyer.com/perspectives/">Tom Sawyer Perspectives</a> - Advanced graphics-based software for building enterprise-class data relationship visualization and analysis applications.</li>
          </ul>
          <a name="committers"></a>
          <a name="contributors"></a>
@@ -303,14 +310,21 @@
          development, testing, documentation, etc. skills to the group. These individuals contribute to TinkerPop beyond the ever-changing requirements of their day-to-day jobs and maintain
          responsibility for their contributions through time.
          <p/>
-         <!-- to be uncommented as necessary, just establishing the template -----------
          <h4 id="contributors-active">Active</h4>
-         -->
          <ul>
-            <li><a href="http://markorodriguez.com">Marko A. Rodriguez</a> (2009 - PMC): Gremlin language, Gremlin machine, documentation.</li>
-            <li><a href="http://ketrinadrawsalot.tumblr.com">Ketrina Yim</a> (2009 - Committer): Illustrator, creator of Gremlin and his merry band of robots.</li>
-            <li><a href="http://stephen.genoprime.com/">Stephen Mallette</a> (2011 - PMC Chair): Gremlin Console/Server/Driver, Language Variants and general core development.</li>
-            <li><a href="http://jamesthornton.com/">James Thornton</a> (2013 - PMC): Promotions, evangelism.</li>
+            <li><a href="https://markorodriguez.com">Marko A. Rodriguez</a> (2009 - Founder): Gremlin language, Gremlin machine, documentation.</li>
+            <li><a href="https://www.linkedin.com/in/joshuashinavier/">Joshua Shinavier</a> (2009 - Founder): Graph data models, semantics, and interoperability</li>
+            <li><a href="https://stephen.genoprime.com/">Stephen Mallette</a> (2011 - PMC Chair): Gremlin Console/Server/Driver, Language Variants and general core development.</li>
+            <li><a href="https://github.com/jorgebay">Jorge Bay</a> (2017 - PMC): GraphBinary serialization, JavaScript and .NET libraries, mailing list support.</li>
+            <li><a href="https://github.com/FlorianHockmann/">Florian Hockmann</a> (2017 - PMC): .NET libraries, mailing list support.</li>
+            <li><a href="https://www.kelvinlawrence.net/">Kelvin Lawrence</a> (2017 - Committer): Documentation and mailing list support.</li>
+            <li><a href="https://www.linkedin.com/in/divijvaidya/">Divij Vaidya</a> (2019 - Committer): Gremlin server-client interaction.</li>
+            <li><a href="https://oyvindsabo.com/">Øyvind Sæbø</a> (2021 - Committer): Gremlint query formatter.</li>
+         </ul>
+         <h4 id="contributors-inactive">Inactive</h4>
+         <ul>
+            <li><a href="https://ketrinadrawsalot.tumblr.com">Ketrina Yim</a> (2009 - Committer): Illustrator, creator of Gremlin and his merry band of robots.</li>
+            <li><a href="https://twitter.com/espeed">James Thornton</a> (2013 - PMC): Promotions, evangelism.</li>
             <li><a href="http://gremlin.guru">Daniel Kuppitz</a> (2014 - PMC): Gremlin language design, benchmarking, testing, documentation, mailing list support.</li>
             <li><a href="https://www.linkedin.com/in/hzbarcea">Hadrian Zbarcea</a> (2015 - PMC): Project mentor, provider liason.</li>
             <li><a href="https://github.com/Humbedooh">Daniel Gruno</a> (2015 - PMC): Project mentor, infrastructure liason.</li>
@@ -320,20 +334,11 @@
             <li><a href="https://github.com/twilmes">Ted Wilmes</a> (2015 - PMC): Promotions, mailing list support, benchmarking, sql-gremlin.</li>
             <li><a href="https://github.com/pietermartin">Pieter Martin</a> (2016 - Committer): Gremlin language, Sqlg.</li>
             <li><a href="https://github.com/jbmusso">Jean-Baptiste Musso</a> (2016 - Committer): Gremlin Server testing, Gremlin Driver (Node.js/JavaScript), mailing list support.</li>
-            <li><a href="http://www.michaelpollmeier.com/">Michael Pollmeier</a> (2016 - Committer): Gremlin language, Gremlin-Scala.</li>
+            <li><a href="https://www.michaelpollmeier.com/">Michael Pollmeier</a> (2016 - Committer): Gremlin language, Gremlin-Scala.</li>
             <li><a href="https://github.com/davebshow">David Brown</a> (2016 - Committer): Python libraries, Gremlin Server testing.</li>
             <li><a href="https://github.com/robertdale">Robert Dale</a> (2016 - PMC): Gremlin Console/Server, documentation, mailing list support.</li>
-            <li><a href="https://github.com/jorgebay">Jorge Bay</a> (2017 - PMC): GraphBinary serialization, JavaScript and .NET libraries, mailing list support.</li>
-            <li><a href="https://github.com/FlorianHockmann/">Florian Hockmann</a> (2017 - PMC): .NET libraries, mailing list support.</li>
-            <li><a href="http://www.kelvinlawrence.net/">Kelvin Lawrence</a> (2017 - Committer): Documentation and mailing list support.</li>
-            <li><a href="http://harshthakkar.in/">Harsh Thakkar</a> (2018 - Committer): Gremlin-SPARQL module.</li>
+            <li><a href="https://harshthakkar.in/">Harsh Thakkar</a> (2018 - Committer): Gremlin-SPARQL module.</li>
          </ul>
-         <!-- to be uncommented as necessary, just establishing the template -----------
-         <h4 id="contributors-inactive">Inactive</h4>
-         <ul>
-            <li><a href="http://someone.com/">John Doe</a> (2015 - 2016): Committer/PMC, Module X, Module Y, mailing list support.</li>
-         </ul>
-         -->
       </div>
    </div>
 </div>
diff --git a/docs/site/home/policy.html b/docs/site/home/policy.html
index b1d6bee..6247c86 100644
--- a/docs/site/home/policy.html
+++ b/docs/site/home/policy.html
@@ -27,9 +27,9 @@
       <h3>Provider Listing Policy</h3>
       <p>Graph system and language providers can have the project listed in two locations on the Apache TinkerPop homepage.
          The first location is on the homepage <a href="index.html">index.html</a>. The second is on the homepage <a href="providers.html">providers.html</a>. The policies
-         for each are provided below. Note that the Apache Software Foundation's <a href="http://www.apache.org/foundation/marks/linking">linking policy</a> supercede those
+         for each are provided below. Note that the Apache Software Foundation's <a href="https://www.apache.org/foundation/marks/linking">linking policy</a> supercede those
          stipulated by Apache TinkerPop. All things considered, if your project meets the requirements, please email Apache TinkerPop's
-         <a href="http://mail-archives.apache.org/mod_mbox/incubator-tinkerpop-dev/">developer mailing list</a> requesting that your project be added to a listing.
+         <a href="https://mail-archives.apache.org/mod_mbox/incubator-tinkerpop-dev/">developer mailing list</a> requesting that your project be added to a listing.
       </p>
       <h4>Index Listing Requirements</h4>
       <ul>
@@ -54,8 +54,8 @@
       <a name="graphic-usage-policy"></a>
       <h3>Graphic Usage Policy</h3>
       <p>Apache TinkerPop has a plethora of graphics that the community can use. There are four categories of graphics. These categories and their respective policies are presented
-         below. If you are unsure of the category of a particular graphic, please ask on our <a href="http://mail-archives.apache.org/mod_mbox/incubator-tinkerpop-dev/">developer mailing</a>
-         list before using it. Finally, note that the Apache Software Foundation's <a href="http://www.apache.org/foundation/marks/">trademark policies</a> supercede those stipulated
+         below. If you are unsure of the category of a particular graphic, please ask on our <a href="https://mail-archives.apache.org/mod_mbox/incubator-tinkerpop-dev/">developer mailing</a>
+         list before using it. Finally, note that the Apache Software Foundation's <a href="https://www.apache.org/foundation/marks/">trademark policies</a> supercede those stipulated
          by Apache TinkerPop.
       </p>
       <ul>
@@ -65,7 +65,7 @@
          <img src="img/policy/gremlin-gremopoly.png" style="padding:10px;width:10%;"/> <img src="img/policy/gremlin-gremreaper.png" style="padding:10px;width:14%;"/> <img src="img/policy/gremlin-chickenwing.png" style="padding:10px;width:10%;"/> <img src="img/policy/gremlin-no-more-mr-nice-guy.png" style="padding:10px;width:10%;"/> <img src="img/policy/gremlin-new-sheriff-in-town.png" style="padding:10px;width:12%;"/> <img src="img/policy/gremlin-gremstefani.png" style="padding:10px;width:10%;"/>
          <li><strong>Explanatory Diagrams</strong>: Explanatory diagrams can be used <em>without permission</em> as long as they are being used in an Apache TinkerPop related context, it is acknowledged that they are trademarks of the Apache Software Foundation/Apache TinkerPop, and are being used for technical explanatory purposes.</li>
          <img src="img/policy/olap-traversal.png" style="padding:10px;width:22%;"/> <img src="img/policy/cyclicpath-step.png" style="padding:10px;width:22%;"/> <img src="img/policy/flat-map-lambda.png" style="padding:10px;width:15%;"/> <img src="img/policy/adjacency-list.png" style="padding:10px;width:22%;"/>
-         <li><strong>Character Scene Graphics</strong>: Character scene graphics <u><em>require permission</em></u> before being used. Please ask for permission on the Apache TinkerPop <a href="http://mail-archives.apache.org/mod_mbox/incubator-tinkerpop-dev/">developer mailing list</a>.</li>
+         <li><strong>Character Scene Graphics</strong>: Character scene graphics <u><em>require permission</em></u> before being used. Please ask for permission on the Apache TinkerPop <a href="https://mail-archives.apache.org/mod_mbox/incubator-tinkerpop-dev/">developer mailing list</a>.</li>
          <img src="img/policy/tinkerpop-reading.png" style="padding:10px;width:20%;"/> <img src="img/policy/gremlintron.png" style="padding:10px;width:20%;"/> <img src="img/policy/business-gremlin.png" style="padding:10px;width:20%;"/> <img src="img/policy/tinkerpop3-splash.png" style="padding:10px;width:20%;"/>
       </ul>
    </div>
diff --git a/docs/site/home/providers.html b/docs/site/home/providers.html
index eba92cb..82ee621 100644
--- a/docs/site/home/providers.html
+++ b/docs/site/home/providers.html
@@ -26,7 +26,7 @@
    <div class="container">
       <div class="row">
          <div class="col-sm-10 col-md-10">
-            <p><a href="http://tinkerpop.apache.org">Apache TinkerPop</a> grows when 3<sup>rd</sup> party data systems and query languages utilize it. While Apache's distribution of TinkerPop
+            <p><a href="https://tinkerpop.apache.org">Apache TinkerPop</a> grows when 3<sup>rd</sup> party data systems and query languages utilize it. While Apache's distribution of TinkerPop
                does provide production ready implementations and tools, it is ultimately the larger ecosystem of providers that ensure TinkerPop's widespread adoption.
                There are two types of providers. The first are those that develop a (graph) database, (graph) processor, or (graph) analytics tool and want to
                offer their users TinkerPop-specific graph computing features. The other type of provider are language designers that have a (graph) query language they
@@ -41,7 +41,7 @@
    <div class="container">
       <a name="data-system-providers"></a>
       <h3>Data System Providers</h3>
-      <p>When a data system is TinkerPop-enabled, its users are able to model their domain as a graph and analyze that graph using the <a href="http://tinkerpop.apache.org/gremlin.html">Gremlin graph traversal language</a>. Furthermore, all
+      <p>When a data system is TinkerPop-enabled, its users are able to model their domain as a graph and analyze that graph using the <a href="https://tinkerpop.apache.org/gremlin.html">Gremlin graph traversal language</a>. Furthermore, all
          TinkerPop-enabled graph systems integrate with one another allowing providers to easily expand their system's offerings as well as allowing users to choose appropriate graph technology for their
          application. Sometimes an application is best served by an in-memory, transactional graph database. Sometimes a multi-machine distributed graph database will do the job. Or perhaps the
          application requires both a distributed graph database for real-time queries and, in parallel, a Big(Graph)Data processor for batch analytics.  Whatever the application's requirements, there
@@ -69,7 +69,7 @@
       <br/>
       <ol>
          <li><strong>The Graph (required)</strong>: These foundational interfaces define the semantics of the operations on a graph, vertex, edge, and property. Once implemented, the provider's
-            data system can immediately be queried using Gremlin OLTP. However, providers may want to leverage a collection of provider-specific compiler optimizations called <a href="http://tinkerpop.apache.org/docs/current/reference/#traversalstrategy">traversal strategies</a>
+            data system can immediately be queried using Gremlin OLTP. However, providers may want to leverage a collection of provider-specific compiler optimizations called <a href="https://tinkerpop.apache.org/docs/current/reference/#traversalstrategy">traversal strategies</a>
             which can leverage their system's unique features (e.g. global indices, vertex-centric indices, sort orders, sequential scanners, push-down predicates, etc.).
          </li>
          <br/>
@@ -79,7 +79,7 @@
             of TinkerPop).
          </li>
       </ol>
-      <p>Finally, there are other tools and technologies that the provider can leverage from TinkerPop such as <a href="http://tinkerpop.apache.org/docs/current/reference/#gremlin-server">Gremlin Server</a>, <a href="http://tinkerpop.apache.org/docs/current/reference/#gremlin-console">Gremlin Console</a>, and the like. The purpose of Apache TinkerPop is to
+      <p>Finally, there are other tools and technologies that the provider can leverage from TinkerPop such as <a href="https://tinkerpop.apache.org/docs/current/reference/#gremlin-server">Gremlin Server</a>, <a href="https://tinkerpop.apache.org/docs/current/reference/#gremlin-console">Gremlin Console</a>, and the like. The purpose of Apache TinkerPop is to
          make it easy for providers to add graph functionality to their system and/or to build a graph system from scratch and immediately have a query language, server infrastructure, metrics/reporting
          integration, cluster-based analytics and more.
       </p>
@@ -89,32 +89,32 @@
          </li>
          <li><strong>Gremlin traversal machine</strong>: Every Gremlin language variant compiles to a language agnostic <a href="https://en.wikipedia.org/wiki/Bytecode">bytecode</a> representation. That bytecode is ultimately translated to a machine-specific traversal. It is the responsibility of the Gremlin traversal machine to execute that traversal as a
             real-time <a href="https://en.wikipedia.org/wiki/Online_transaction_processing">OLTP</a> query or as an analytic <a href="https://en.wikipedia.org/wiki/Online_analytical_processing">OLAP</a> query (or both). Note that the Gremlin traversal machine is not bound to the Gremlin language. Any language can take advantage of the the
-            Gremlin traversal machine by simply translating itself to Gremlin bytecode. In fact, compilers currently exist for <a href="https://github.com/twilmes/sql-gremlin">SQL</a> and <a href="http://tinkerpop.apache.org/docs/current/reference/#sparql-gremlin">SPARQL</a>. However, using alternative languages for graph computing leads to significantly more complicated queries
+            Gremlin traversal machine by simply translating itself to Gremlin bytecode. In fact, compilers currently exist for <a href="https://github.com/twilmes/sql-gremlin">SQL</a> and <a href="https://tinkerpop.apache.org/docs/current/reference/#sparql-gremlin">SPARQL</a>. However, using alternative languages for graph computing leads to significantly more complicated queries
             and typically does not match the expressivity provided by Gremlin.
          </li>
-         <li><strong>TinkerGraph</strong>: TinkerPop provides a simple, non-transactional, in-memory graph system called <a href="http://tinkerpop.apache.org/docs/current/reference/#tinkergraph-gremlin">TinkerGraph</a>. TinkerGraph is useful for exploring graphs that can fit
+         <li><strong>TinkerGraph</strong>: TinkerPop provides a simple, non-transactional, in-memory graph system called <a href="https://tinkerpop.apache.org/docs/current/reference/#tinkergraph-gremlin">TinkerGraph</a>. TinkerGraph is useful for exploring graphs that can fit
             in-memory, for doing tutorials and training without the overhead of database setup, etc. TinkerGraph boasts both OLTP and OLAP traversal machine support.
          </li>
-         <li><strong>Gremlin Console</strong>: A command line <a href="https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop">REPL</a> is provided called <a href="http://tinkerpop.apache.org/docs/current/reference/#gremlin-console">Gremlin Console</a>. This console is useful when learning TinkerPop as users can load provided datasets into a
+         <li><strong>Gremlin Console</strong>: A command line <a href="https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop">REPL</a> is provided called <a href="https://tinkerpop.apache.org/docs/current/reference/#gremlin-console">Gremlin Console</a>. This console is useful when learning TinkerPop as users can load provided datasets into a
             graph system and explore the Gremlin language without the overhead of creating a full-blown software project. Furthermore, the Gremlin Console is used extensively in production scenarios
             because it allows system administrators to interact with a local or remote graph to gather statistics, manually explore the data to ensure data integrity, and other useful tasks.
          </li>
-         <li><strong>Gremlin Server</strong>: It is typical for a graph database to exist on a separate machine from the user's application code. <a href="http://tinkerpop.apache.org/docs/current/reference/#gremlin-server">Gremlin Server</a> bridges the network-divide
+         <li><strong>Gremlin Server</strong>: It is typical for a graph database to exist on a separate machine from the user's application code. <a href="https://tinkerpop.apache.org/docs/current/reference/#gremlin-server">Gremlin Server</a> bridges the network-divide
             allowing users to seamlessly submit traversals for remote execution over a web-sockets based binary protocol. If provider already has a server, they can leverage TinkerPop-specific
             components as needed (e.g. implement <code>RemoteConnection</code>). Gremlin Server also provides an HTTP-based API, support for <a href="http://ganglia.info/">Ganglia</a>/<a href="http://graphite.wikidot.com/">Graphite</a>/<a href="http://www.oracle.com/technetwork/articles/java/javamanagement-140525.html">JMX</a>/more
             metrics, and a traversal routing framework for intelligent data/traversal co-location within a distributed graph database's machine cluster.
          </li>
-         <li><strong>SparkGraphComputer</strong>: <a href="http://spark.apache.org/">Apache Spark</a>&trade; is a Big Data OLAP processor that simplifies the creation and execution of distributed data analytics.
-            <a href="http://tinkerpop.apache.org/docs/current/reference/#sparkgraphcomputer"><code>SparkGraphComputer</code></a> turns Spark
+         <li><strong>SparkGraphComputer</strong>: <a href="https://spark.apache.org/">Apache Spark</a>&trade; is a Big Data OLAP processor that simplifies the creation and execution of distributed data analytics.
+            <a href="https://tinkerpop.apache.org/docs/current/reference/#sparkgraphcomputer"><code>SparkGraphComputer</code></a> turns Spark
             into a Big(Graph)Data processor via the OLAP component of the Gremlin traversal machine. Users do not have to learn Spark's data processing language as Gremlin traversals execute
             over Spark. For graph system providers, they can boast Spark integration once a custom <code>InputRDD</code> (or <code>InputFormat</code>) is developed.
          </li>
-         <li><strong>Hadoop support</strong>: <a href="http://hadoop.apache.org/">Apache Hadoop</a>&reg; has become a staple technology for Big Data applications. In TinkerPop, <code>SparkGraphComputer</code> can pull data
+         <li><strong>Hadoop support</strong>: <a href="https://hadoop.apache.org/">Apache Hadoop</a>&reg; has become a staple technology for Big Data applications. In TinkerPop, <code>SparkGraphComputer</code> can pull data
             from the Hadoop File System (<a href="https://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-hdfs/HdfsUserGuide.html">HDFS</a>). TinkerPop provides a collection of Input- and OutputFormats for different graph serialization standards as well as tooling that makes it easy for users
-            to <a href="http://tinkerpop.apache.org/docs/current/reference/#interacting-with-hdfs">interact with HDFS</a> from the Gremlin Console or their application.
+            to <a href="https://tinkerpop.apache.org/docs/current/reference/#interacting-with-hdfs">interact with HDFS</a> from the Gremlin Console or their application.
          </li>
       </ul>
-      <p>Information on how to build implementations of the various interfaces that TinkerPop supports can be found in the <a href="http://tinkerpop.apache.org/docs/current/dev/provider/">Provider Documentation</a>.
+      <p>Information on how to build implementations of the various interfaces that TinkerPop supports can be found in the <a href="https://tinkerpop.apache.org/docs/current/dev/provider/">Provider Documentation</a>.
       <br/>
       <h4>TinkerPop-Enabled Graph Systems</h4>
       <br/>
@@ -135,57 +135,67 @@
       <br/>
       <div class="row">
           <div class="col-sm-6 col-md-6">
-            <a href="http://datastax.com/products/datastax-enterprise-graph"><img src="img/logos/datastax-logo.png" style="padding-right:20px;float:left;width:35%;"></a>
-            <a href="http://datastax.com/products/datastax-enterprise-graph">DataStax Enterprise Graph</a>&trade;, part of DataStax Enterprise's multi-model platform, is a real-time graph database built for cloud applications that need to manage complex and highly connected data. Built on the foundation of Apache Cassandra and Apache TinkerPop, DataStax Enterprise Graph delivers continuous uptime along with predictable performance and scale, while remaining operationally simple to manage.
+            <a href="https://datastax.com/products/datastax-enterprise-graph"><img src="img/logos/datastax-logo.png" style="padding-right:20px;float:left;width:35%;"></a>
+            <a href="https://datastax.com/products/datastax-enterprise-graph">DataStax Enterprise Graph</a>&trade;, part of DataStax Enterprise's multi-model platform, is a real-time graph database built for cloud applications that need to manage complex and highly connected data. Built on the foundation of Apache Cassandra and Apache TinkerPop, DataStax Enterprise Graph delivers continuous uptime along with predictable performance and scale, while remaining operationally simple to manage.
          </div>
          <div class="col-sm-6 col-md-6">
+            <a href="https://github.com/hugegraph/hugegraph"><img src="img/logos/hugegraph-logo.png" style="padding-right:20px;float:left;width:35%;"></a>
+            <a href="https://github.com/hugegraph/hugegraph">HugeGraph</a> is an Apache2 licensed high-speed, distributed and scalable OLTP and OLAP graph database, fully optimized to store hundreds of billions vertices/edges and analyze complex relationships between high-connected data. It is modeled as property graph and compatible with Apache TinkerPop and Gremlin. Due to high efficiency, availability and scalability, HugeGraph attracts a large amount of users and has been widely used in social network analysis, fraud detection and knowledge graph.
+         </div>
+      </div>
+      <br/>
+      <div class="row">
+         <div class="col-sm-6 col-md-6">
             <a href="https://grakn.ai/"><img src="img/logos/grakn-logo.png" style="padding-right:20px;float:left;width:35%;"></a>
             <a href="https://grakn.ai/">GRAKN.AI</a>&trade; is a distributed knowledge graph that brings knowledge ontologies and transactional data together to enable intelligent querying of data. Querying is performed through the language: Graql, a declarative, knowledge-oriented graph query language for retrieving explicitly stored and implicitly derived information, as well as to perform graph analytics and automated reasoning.
          </div>
-      </div>
-      <br/>
-      <div class="row">
          <div class="col-sm-6 col-md-6">
             <a href="https://compose.com/databases/janusgraph"><img src="img/logos/ibm-compose-janusgraph-logo.png" style="padding-right:20px;float:left;width:35%;"></a>
             IBM&reg; <a href="https://compose.com/databases/janusgraph">Compose for JanusGraph</a> provides a fully-managed, highly-available, and production-ready JanusGraph on AWS, GCP or IBM Cloud. Deployed in minutes, every JanusGraph deployment on Compose is built with highly available storage and graph engines. The JanusGraph Storage engine is a cluster of the Scylla database. As usage increases or application requirements change, users can vertically or horizontally scale the JanusGraph Engine and Storage to increase throughput or storage.
          </div>
-         <div class="col-sm-6 col-md-6">
-           <a href="http://janusgraph.org/"><img src="img/logos/janusgraph-logo.png" style="padding-right:20px;float:left;width:35%;"></a>
-           <a href="http://janusgraph.org/">JanusGraph</a>&reg; is an Apache2 licensed scalable, distributed graph database optimized for storing and querying graphs containing hundreds of billions of vertices and edges distributed across a multi-machine cluster. JanusGraph is a transactional database that can support thousands of concurrent users executing complex Gremlin traversals in real time. JanusGraph also provides an in-memory, compression-based OLAP processor as well as integrates with Apache TinkerPop's Spark OLAP processors.
-         </div>
       </div>
       <br/>
       <div class="row">
          <div class="col-sm-6 col-md-6">
+            <a href="http://janusgraph.org/"><img src="img/logos/janusgraph-logo.png" style="padding-right:20px;float:left;width:35%;"></a>
+            <a href="http://janusgraph.org/">JanusGraph</a>&reg; is an Apache2 licensed scalable, distributed graph database optimized for storing and querying graphs containing hundreds of billions of vertices and edges distributed across a multi-machine cluster. JanusGraph is a transactional database that can support thousands of concurrent users executing complex Gremlin traversals in real time. JanusGraph also provides an in-memory, compression-based OLAP processor as well as integrates with Apache TinkerPop's Spark OLAP processors.
+         </div>
+         <div class="col-sm-6 col-md-6">
            <a href="http://cambridge-intelligence.com/keylines/"><img src="img/logos/keylines-logo.png" style="padding-right:20px;float:left;width:35%;"></a>
            <a href="http://cambridge-intelligence.com/keylines/">KeyLines</a>&trade; is an Apache TinkerPop and Gremlin compatible JavaScript SDK for quickly and easily building powerful, custom and scalable graph visualization applications. The KeyLines SDK offers a rich library of functionality to help you visualize and explore the data in your graph database, including graph layouts, social network analysis measures, filtering, temporal graph visualization and geospatial graph analysis. It allows the visualization of complex graph data at scale.
          </div>
-         <div class="col-sm-6 col-md-6">
-           <a href="http://linkurio.us/"><img src="img/logos/linkurious-logo.png" style="padding-right:20px;float:left;width:35%;"></a>
-           <a href="http://linkurio.us/">Linkurious</a>&trade; is a browser-based graph visualization software to search, explore and visualize connected data. It is compatible with Apache TinkerPop and thus, any TinkerPop-enabled graph system. Linkurious provides enterprise-ready security (authentication, access rights, audit) and flexibility (API, linkurious.js JS graph visualization library) to help software architects successfully deploy graph capabilities within their organizations.
-         </div>
       </div>
       <br/>
       <div class="row">
          <div class="col-sm-6 col-md-6">
+            <a href="http://linkurio.us/"><img src="img/logos/linkurious-logo.png" style="padding-right:20px;float:left;width:35%;"></a>
+            <a href="http://linkurio.us/">Linkurious</a>&trade; is a browser-based graph visualization software to search, explore and visualize connected data. It is compatible with Apache TinkerPop and thus, any TinkerPop-enabled graph system. Linkurious provides enterprise-ready security (authentication, access rights, audit) and flexibility (API, linkurious.js JS graph visualization library) to help software architects successfully deploy graph capabilities within their organizations.
+         </div>
+         <div class="col-sm-6 col-md-6">
            <a href="http://neo4j.com/"><img src="img/logos/neo4j-logo.png" style="padding-right:20px;float:left;width:35%;"></a>
            <a href="http://neo4j.com/">Neo4j</a>&trade; is the most widely used open source, transactional graph database with a large active user and customer community. Because of its scalability and ease of use, Neo4j is applied in a wide variety of use cases from fraud detection, access control to recommendation and investigative journalism. Along with the openCypher graph query language, Neo4j also supports Apache TinkerPop and currently serves as its OLTP reference implementation.
          </div>
+      </div>
+      <br/>
+      <div class="row">
          <div class="col-sm-6 col-md-6">
-           <a href="http://orientdb.com/"><img src="img/logos/orientdb-logo.png" style="padding-right:20px;float:left;width:35%;"></a>
-           <a href="http://orientdb.com/">OrientDB</a>&trade; is an open source distributed graph database with native support for Apache TinkerPop and the Gremlin graph traversal language. OrientDB handles relationships by using persistent pointers, rather than expensive join runtime operations. This guarantees a fast, constant O(1) time for traversing, no matter the database size. Furthermore, OrientDB is not only a graph database, but a multi-model database able to manage documents, keys/values, objects, full-text and spatial data.
+            <a href="http://orientdb.com/"><img src="img/logos/orientdb-logo.png" style="padding-right:20px;float:left;width:35%;"></a>
+            <a href="http://orientdb.com/">OrientDB</a>&trade; is an open source distributed graph database with native support for Apache TinkerPop and the Gremlin graph traversal language. OrientDB handles relationships by using persistent pointers, rather than expensive join runtime operations. This guarantees a fast, constant O(1) time for traversing, no matter the database size. Furthermore, OrientDB is not only a graph database, but a multi-model database able to manage documents, keys/values, objects, full-text and spatial data.
+         </div>
+         <div class="col-sm-6 col-md-6">
+           <a href="http://stardog.com/"><img src="img/logos/stardog-logo.png" style="padding-right:20px;float:left;width:35%;"></a>
+           <a href="http://stardog.com/">Stardog</a>&trade; is a graph database optimized for enterprise data unification. It supports both semantic graphs, via RDF, SPARQL, and OWL, as well as property graphs via Apache TinkerPop and Gremlin--it's the only graph database that supports both models over the same database, simultaneously. Stardog also supports hybrid data unification architectures, seamlessly blending data warehouse, system of record, and virtual query strategies. Stardog is suited for enterprise data silo challenges.
          </div>
       </div>
       <br/>
       <div class="row">
          <div class="col-sm-6 col-md-6">
-           <a href="http://stardog.com/"><img src="img/logos/stardog-logo.png" style="padding-right:20px;float:left;width:35%;"></a>
-           <a href="http://stardog.com/">Stardog</a>&trade; is a graph database optimized for enterprise data unification. It supports both semantic graphs, via RDF, SPARQL, and OWL, as well as property graphs via Apache TinkerPop and Gremlin--it's the only graph database that supports both models over the same database, simultaneously. Stardog also supports hybrid data unification architectures, seamlessly blending data warehouse, system of record, and virtual query strategies. Stardog is suited for enterprise data silo challenges.
-         </div>
-         <div class="col-sm-6 col-md-6">
             <a href="http://tomsawyer.com/products/perspectives/"><img src="img/logos/tomsawyer-logo.png" style="padding-right:20px;float:left;width:35%;"></a>
             <a href="http://tomsawyer.com/products/perspectives/">Tom Sawyer Perspectives</a>&trade; is advanced graphics-based software for building enterprise-class data relationship visualization and analysis applications. It is a complete Software Development Kit (SDK) with a graphics-based design and preview environment. Tom Sawyer Perspectives combines visualization, layout, and analysis technology with an elegant platform architecture. Tom Sawyer Perspectives enables interaction with graph database systems via Apache TinkerPop.
          </div>
+         <div class="col-sm-6 col-md-6">
+            &nbsp;
+         </div>
       </div>
    </div>
    <br/>
@@ -222,7 +232,7 @@
          <div class="col-sm-8 col-md-9">
             <br/>
             <strong>Distinct query language</strong>: Query languages such as SQL and SPARQL are significantly different from Gremlin in that they require a special purpose compiler in order to
-            generate a traversal. For this reason, <a href="https://github.com/twilmes/sql-gremlin">SQL</a> and <a href="http://tinkerpop.apache.org/docs/current/reference/#sparql-gremlin">SPARQL</a> Gremlin compilers
+            generate a traversal. For this reason, <a href="https://github.com/twilmes/sql-gremlin">SQL</a> and <a href="https://tinkerpop.apache.org/docs/current/reference/#sparql-gremlin">SPARQL</a> Gremlin compilers
             currently exist. Note that, within reason, Gremlin compilers do not need to concern themselves with an optimal compilation (only a semantically correct compilation) as the Gremlin
             traversal machine will leverage traversal strategies for both compile-time and runtime optimizations. Moreover, the language designer can rest assured that queries in their language
             will be able to evaluate as either an OLTP or OLAP query. The example on the right is a SPARQL query that determines the average rating for Gremlin's friends' projects. It is because
@@ -243,7 +253,7 @@
       <br/>
       <div class="row">
          <div class="col-sm-7 col-md-8">
-            <strong>Gremlin language variants</strong>: There are various <a href="http://tinkerpop.apache.org/docs/current/tutorials/gremlin-language-variants/">Gremlin language variants</a> such as <a href="http://tinkerpop.apache.org/docs/current/reference/#gremlin-python">Gremlin-Python</a>. These languages
+            <strong>Gremlin language variants</strong>: There are various <a href="https://tinkerpop.apache.org/docs/current/reference/#gremlin-drivers-variants">Gremlin language variants</a> such as <a href="https://tinkerpop.apache.org/docs/current/reference/#gremlin-python">Gremlin-Python</a>. These languages
             generate Gremlin bytecode utilizing the same naming/style-conventions as Gremlin-Java. However, where appropriate, they can deviate from convention in order to take advantage of the unique expressive qualities of the host language. For instance, Gremlin-Python supports index slices, attribute access, etc.
          </div>
          <div class="col-sm-5 col-md-4">
@@ -275,23 +285,23 @@
       <br/>
       <div class="row">
          <div class="col-sm-6 col-md-6">
-            <a href="http://tinkerpop.apache.org/docs/current/reference/#gremlin-console"><img src="img/logos/gremlin-groovy-logo.png" style="padding-right:20px;float:left;width:35%;"></a>
-            <a href="http://tinkerpop.apache.org/docs/current/reference/#gremlin-console">Gremlin-Groovy</a> represents Gremlin inside the Groovy language and can be leveraged by any JVM-based project either through gmaven or its JSR-223 ScriptEngine implementation. It also serves as the Gremlin Console language.
+            <a href="https://tinkerpop.apache.org/docs/current/reference/#gremlin-console"><img src="img/logos/gremlin-groovy-logo.png" style="padding-right:20px;float:left;width:35%;"></a>
+            <a href="https://tinkerpop.apache.org/docs/current/reference/#gremlin-console">Gremlin-Groovy</a> represents Gremlin inside the Groovy language and can be leveraged by any JVM-based project either through gmaven or its JSR-223 ScriptEngine implementation. It also serves as the Gremlin Console language.
          </div>
          <div class="col-sm-6 col-md-6">
-            <a href="http://tinkerpop.apache.org/docs/current/reference/#_on_gremlin_language_variants"><img src="img/logos/gremlin-java-logo.png" style="padding-right:20px;float:left;width:35%;"></a>
-            <a href="http://tinkerpop.apache.org/docs/current/reference/#_on_gremlin_language_variants">Gremlin-Java</a> represents Gremlin inside the Java8 language. Gremlin-Java is considered the canonical, reference implementation of Gremlin and is the primary compiler for all lambda-free bytecode due to its speed relative to other script-based, JVM variants.
+            <a href="https://tinkerpop.apache.org/docs/current/reference/#_on_gremlin_language_variants"><img src="img/logos/gremlin-java-logo.png" style="padding-right:20px;float:left;width:35%;"></a>
+            <a href="https://tinkerpop.apache.org/docs/current/reference/#_on_gremlin_language_variants">Gremlin-Java</a> represents Gremlin inside the Java language. Gremlin-Java is considered the canonical, reference implementation of Gremlin and is the primary compiler for all lambda-free bytecode due to its speed relative to other script-based, JVM variants.
          </div>
       </div>
       <br/>
       <div class="row">
          <div class="col-sm-6 col-md-6">
-            <a href="http://tinkerpop.apache.org/docs/current/reference/#gremlin-python"><img src="img/logos/gremlin-python-logo.png" style="padding-right:20px;float:left;width:35%;"></a>
-            <a href="http://tinkerpop.apache.org/docs/current/reference/#gremlin-python">Gremlin-Python</a> represents Gremlin inside the Python language and can be used by any Python virtual machine such as CPython and Jython. Gremlin-Python traversals translate to Gremlin bytecode for RemoteConnection execution (e.g. Gremlin Server).
+            <a href="https://tinkerpop.apache.org/docs/current/reference/#gremlin-python"><img src="img/logos/gremlin-python-logo.png" style="padding-right:20px;float:left;width:35%;"></a>
+            <a href="https://tinkerpop.apache.org/docs/current/reference/#gremlin-python">Gremlin-Python</a> represents Gremlin inside the Python language and can be used by any Python virtual machine such as CPython. Gremlin-Python traversals translate to Gremlin bytecode for RemoteConnection execution (e.g. Gremlin Server).
          </div>
          <div class="col-sm-6 col-md-6">
-            <a href="http://tinkerpop.apache.org/docs/current/reference/#gremlin-DotNet"><img src="img/logos/gremlin-dotnet-logo.png" style="padding-right:20px;float:left;width:35%;"></a>
-            <a href="http://tinkerpop.apache.org/docs/current/reference/#gremlin-DotNet">Gremlin.Net</a> represents Gremlin inside the C# language and can be used by any .NET-based project. Gremlin.Net traversals translate to Gremlin bytecode for RemoteConnection execution (e.g. Gremlin Server).
+            <a href="https://tinkerpop.apache.org/docs/current/reference/#gremlin-DotNet"><img src="img/logos/gremlin-dotnet-logo.png" style="padding-right:20px;float:left;width:35%;"></a>
+            <a href="https://tinkerpop.apache.org/docs/current/reference/#gremlin-DotNet">Gremlin.Net</a> represents Gremlin inside the C# language and can be used by any .NET-based project. Gremlin.Net traversals translate to Gremlin bytecode for RemoteConnection execution (e.g. Gremlin Server).
          </div>
       </div>
       <br/>
@@ -308,8 +318,8 @@
       <br/>
       <div class="row">
          <div class="col-sm-6 col-md-6">
-            <a href="http://tinkerpop.apache.org/docs/current/reference/#sparql-gremlin"><img src="img/logos/sparql-gremlin-logo.png" style="padding-right:20px;float:left;width:35%;"></a>
-            <a href="http://tinkerpop.apache.org/docs/current/reference/#sparql-gremlin">SPARQL-Gremlin</a> is a compiler used to transform SPARQL queries into Gremlin bytecode. It is based on the Apache Jena SPARQL processor ARQ, which provides access to a syntax tree of a SPARQL query.
+            <a href="https://tinkerpop.apache.org/docs/current/reference/#sparql-gremlin"><img src="img/logos/sparql-gremlin-logo.png" style="padding-right:20px;float:left;width:35%;"></a>
+            <a href="https://tinkerpop.apache.org/docs/current/reference/#sparql-gremlin">SPARQL-Gremlin</a> is a compiler used to transform SPARQL queries into Gremlin bytecode. It is based on the Apache Jena SPARQL processor ARQ, which provides access to a syntax tree of a SPARQL query.
          </div>
          <div class="col-sm-6 col-md-6">
             <a href="https://github.com/twilmes/sql-gremlin"><img src="img/logos/sql-gremlin-logo.png" style="padding-right:20px;float:left;width:35%;"></a>
diff --git a/docs/site/home/template/header-footer.html b/docs/site/home/template/header-footer.html
index 1947063..258043e 100644
--- a/docs/site/home/template/header-footer.html
+++ b/docs/site/home/template/header-footer.html
@@ -26,7 +26,7 @@
       <meta http-equiv="X-UA-Compatible" content="IE=edge">
       <meta name="viewport" content="width=device-width, initial-scale=1">
       <title>Apache TinkerPop</title>
-      <meta name="description" content="A Graph Computing Framework">
+      <meta name="description" content="Apache TinkerPop: A Graph Computing Framework">
       <meta name="author" content="Apache TinkerPop">
       <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
       <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
@@ -65,7 +65,7 @@
             <span class="icon-bar"></span>
             <span class="icon-bar"></span>
             </button>
-            <a class="navbar-brand" href="http://tinkerpop.apache.org"><font face="american typewriter"><b>Apache TinkerPop</b></font></a>
+            <a class="navbar-brand" href="https://tinkerpop.apache.org"><font face="american typewriter"><b>Apache TinkerPop</b></font></a>
          </div>
          <div id="navbar-collapse-1" class="collapse navbar-collapse">
             <ul class="nav navbar-nav">
@@ -75,32 +75,31 @@
                   Documentation <b class="caret"></b>
                   </a>
                   <ul class="dropdown-menu">
-                     <li class="dropdown-header">Latest: 3.4.2 (28-May-2019)</li>
-                     <li><a href="http://tinkerpop.apache.org/docs/current">TinkerPop 3.4.2</a></li>
-                     <li><a href="http://tinkerpop.apache.org/docs/current/upgrade">Upgrade Information</a></li>
-                     <li><a href="http://tinkerpop.apache.org/javadocs/current/core/">Core Javadoc API</a></li>
-                     <li><a href="http://tinkerpop.apache.org/javadocs/current/full/">Full Javadoc API</a></li>
+                     <li class="dropdown-header">Latest: 3.5.0 (3-May-2021)</li>
+                     <li><a href="https://tinkerpop.apache.org/docs/current">TinkerPop 3.5.0</a></li>
+                     <li><a href="https://tinkerpop.apache.org/docs/current/upgrade">Upgrade Information</a></li>
+                     <li><a href="https://tinkerpop.apache.org/javadocs/current/core/">Core Javadoc API</a></li>
+                     <li><a href="https://tinkerpop.apache.org/javadocs/current/full/">Full Javadoc API</a></li>
                      <li role="separator" class="divider"></li>
-                     <li class="dropdown-header">Maintenance: 3.3.7 (28-May-2019)</li>
-                     <li><a href="http://tinkerpop.apache.org/docs/3.3.7/">TinkerPop 3.3.6</a></li>
-                     <li><a href="http://tinkerpop.apache.org/javadocs/3.3.7/core/">Core Javadoc API</a></li>
-                     <li><a href="http://tinkerpop.apache.org/javadocs/3.3.7/full/">Full Javadoc API</a></li>
+                     <li class="dropdown-header">Maintenance: 3.4.11 (3-May-2021)</li>
+                     <li><a href="https://tinkerpop.apache.org/docs/3.4.11/">TinkerPop 3.4.11</a></li>
+                     <li><a href="https://tinkerpop.apache.org/javadocs/3.4.11/core/">Core Javadoc API</a></li>
+                     <li><a href="https://tinkerpop.apache.org/javadocs/3.4.11/full/">Full Javadoc API</a></li>
                      <li role="separator" class="divider"></li>
-                     <li><a href="http://tinkerpop.apache.org/docs/">Documentation Archives</a></li>
-                     <li><a href="http://tinkerpop.apache.org/javadocs/">Javadoc Archives</a></li>
+                     <li><a href="https://tinkerpop.apache.org/docs/">Documentation Archives</a></li>
+                     <li><a href="https://tinkerpop.apache.org/javadocs/">Javadoc Archives</a></li>
                      <li role="separator" class="divider"></li>
-                     <li><a href="http://tinkerpop.apache.org/docs/current/index.html#publications">Publications</a></li>
+                     <li><a href="https://tinkerpop.apache.org/docs/current/index.html#publications">Publications</a></li>
                   </ul>
                </li>
                <li class="dropdown">
                   <a class="dropdown-toggle" data-toggle="dropdown" href="#">Tutorials<b class="caret"></b></a>
                   <ul class="dropdown-menu">
                      <li><a href="gremlin.html">Introduction to Gremlin</a></li>
-                     <li><a href="http://tinkerpop.apache.org/docs/current/tutorials/getting-started/">Getting Started</a></li>
-                     <li><a href="http://tinkerpop.apache.org/docs/current/tutorials/the-gremlin-console/">The Gremlin Console</a></li>
-                     <li><a href="http://tinkerpop.apache.org/docs/current/recipes/">Gremlin Recipes</a></li>
-                     <li><a href="http://tinkerpop.apache.org/docs/current/tutorials/gremlin-language-variants/">Gremlin Language Variants</a></li>
-                     <li><a href="http://tinkerpop.apache.org/docs/current/tutorials/gremlins-anatomy/">Gremlin's Anatomy</a></li>
+                     <li><a href="https://tinkerpop.apache.org/docs/current/tutorials/getting-started/">Getting Started</a></li>
+                     <li><a href="https://tinkerpop.apache.org/docs/current/tutorials/the-gremlin-console/">The Gremlin Console</a></li>
+                     <li><a href="https://tinkerpop.apache.org/docs/current/recipes/">Gremlin Recipes</a></li>
+                     <li><a href="https://tinkerpop.apache.org/docs/current/tutorials/gremlins-anatomy/">Gremlin's Anatomy</a></li>
                      <li role="separator" class="divider"></li>
                      <li><a href="http://kelvinlawrence.net/book/Gremlin-Graph-Guide.html">Book: Practical Gremlin by Kelvin Lawrence</a></li>
                      <li><a href="http://sql2gremlin.com/">SQL2Gremlin</a></li>
@@ -123,17 +122,18 @@
                      <li><a href="https://twitter.com/apachetinkerpop">Twitter</a></li>
                   </ul>
                </li>
+               <li><a href="gremlint/">Gremlint</a></li>
                <li class="dropdown">
                   <a href="#" class="dropdown-toggle" data-toggle="dropdown">
                   Apache Software Foundation <b class="caret"></b>
                   </a>
                   <ul class="dropdown-menu">
-                     <li><a href="http://www.apache.org/">Apache Homepage</a></li>
-                     <li><a href="http://www.apache.org/licenses/">License</a></li>
+                     <li><a href="https://www.apache.org/">Apache Homepage</a></li>
+                     <li><a href="https://www.apache.org/licenses/">License</a></li>
                      <li><a href="https://www.apache.org/events/current-event">Events</a></li>
-                     <li><a href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li>
-                     <li><a href="http://www.apache.org/foundation/thanks.html">Thanks</a></li>
-                     <li><a href="http://www.apache.org/security/">Security</a></li>
+                     <li><a href="https://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li>
+                     <li><a href="https://www.apache.org/foundation/thanks.html">Thanks</a></li>
+                     <li><a href="https://www.apache.org/security/">Security</a></li>
                   </ul>
                </li>
             </ul>
@@ -142,7 +142,7 @@
       !!!!!BODY!!!!!
       <div id="footer">
          <div class="container">
-            <p class="muted credit">Copyright © 2015-2019 The Apache Software Foundation.<br/>Apache TinkerPop, TinkerPop, Apache, Apache feather logo, and Apache TinkerPop project logo are either registered trademarks or trademarks of <a href="http://www.apache.org/">The Apache Software Foundation</a> in the United States and other countries.
+            <p class="muted credit">Copyright © 2015-2021 The Apache Software Foundation.<br/>Apache TinkerPop, TinkerPop, Apache, Apache feather logo, and Apache TinkerPop project logo are either registered trademarks or trademarks of <a href="https://www.apache.org/">The Apache Software Foundation</a> in the United States and other countries.
             </p>
          </div>
       </div>
diff --git a/docs/src/dev/developer/contributing.asciidoc b/docs/src/dev/developer/contributing.asciidoc
index fc720d5..3087124 100644
--- a/docs/src/dev/developer/contributing.asciidoc
+++ b/docs/src/dev/developer/contributing.asciidoc
@@ -75,10 +75,10 @@
 
 For both types of documentation, changes can be submitted via pull request. For project documentation, TinkerPop has
 a robust documentation system that is based on link:http://asciidoc.org/[asciidoc]. The content can be found in the
-link:https://github.com/apache/tinkerpop/tree/master/docs/src[docs/src]. Recall that this documentation is version
-specific, so consider the appropriate branch on which to submit the pull request so that the documentation is reflective
-of the version it is tied to. To view generated documentation locally, read more about environment configurations in
-the <<documentation-environment,Documentation Environment>> section.
+link:https://github.com/apache/tinkerpop/tree/master/docs/src[docs/src]. Documentation is version specific, so consider
+the appropriate branch on which to submit the pull request so that the documentation is reflective of the version it is
+tied to. To view generated documentation locally, read more about environment configurations in the
+<<documentation-environment,Documentation Environment>> and <<documentation, Contributor Documentation>> sections.
 
 For web site changes, the process is largely the same except that the documentation system is HTML based instead of
 Asciidoc. The content can be found in the source control tree at link:https://github.com/apache/tinkerpop/tree/master/docs/site[docs/site].
diff --git a/docs/src/dev/developer/development-environment.asciidoc b/docs/src/dev/developer/development-environment.asciidoc
index c02dea8..58764a1 100644
--- a/docs/src/dev/developer/development-environment.asciidoc
+++ b/docs/src/dev/developer/development-environment.asciidoc
@@ -26,9 +26,11 @@
 [[system-configuration]]
 == System Configuration
 
-At a minimum, development of TinkerPop requires link:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html[Java 1.8.0_40+]
-and link:https://maven.apache.org/download.cgi[Maven 3.2.5+]. Maven is used as the common build system, which even
-controls the builds of non-JVM link:https://tinkerpop.apache.org/docs/current/tutorials/gremlin-language-variants/[GLVs]
+At a minimum, development of TinkerPop requires link:https://openjdk.java.net/projects/jdk8/[Java 8] but it is
+preferable to use link:https://openjdk.java.net/projects/jdk/11/[Java 11] cross-compiled to Java 8 (the
+cross-compilation happens automatically as part of the build). Maven (requiring a minimum of
+link:https://maven.apache.org/download.cgi[Maven 3.3.9+]) is used as the common build system, which even
+controls the builds of non-JVM link:https://tinkerpop.apache.org/docs/x.y.z/reference/#gremlin-drivers-variants[GLVs]
 such as `gremlin-python`. Java and Maven are described as a "minimum" for a development environment, because they
 will only build JVM portions of TinkerPop and many integration tests will not fire with this simple setup. It is
 possible to get a clean and successful build with this minimum, but it will not be possible to build non-JVM aspects
@@ -37,6 +39,9 @@
 To gain the ability to execute all aspects of the TinkerPop build system, other environmental configurations must be
 established. Those prerequisites are defined in the following subsections.
 
+IMPORTANT: Use Java 11 for documentation generation with `bin/process-docs.sh` and for other build features outside
+of the basic `mvn clean install` sort of function.
+
 IMPORTANT: For those who intend to offer a contribution, building with a minimal configuration may not be sufficient
 when submitting a pull request. Consider setting up the full environment.
 
@@ -107,11 +112,32 @@
 scripts should work on Mac and Linux.
 
 To generate documentation, it is required that link:https://hadoop.apache.org[Hadoop 2.7.x] is running in
-link:https://hadoop.apache.org/docs/r2.7.2/hadoop-project-dist/hadoop-common/SingleCluster.html#Pseudo-Distributed_Operation[pseudo-distributed]
+link:https://hadoop.apache.org/docs/r2.7.7/hadoop-project-dist/hadoop-common/SingleCluster.html#Pseudo-Distributed_Operation[pseudo-distributed]
 mode. Be sure to set the `HADOOP_GREMLIN_LIBS` environment variable as described in the
 link:https://tinkerpop.apache.org/docs/current/reference/#hadoop-gremlin[reference documentation]. It is also important
 to set the `CLASSPATH` to point at the directory containing the Hadoop configuration files, like `mapred-site.xml`.
 
+The `/etc/hadoop/yarn-site.xml` file prefers this configuration over the one provided in the Hadoop documentation
+referenced above:
+
+[source,xml]
+----
+<configuration>
+    <property>
+        <name>yarn.nodemanager.aux-services</name>
+        <value>mapreduce_shuffle</value>
+    </property>
+    <property>
+        <name>yarn.nodemanager.vmem-check-enabled</name>
+        <value>false</value>
+    </property>
+    <property>
+        <name>yarn.nodemanager.vmem-pmem-ratio</name>
+        <value>4</value>
+    </property>
+</configuration>
+----
+
 Also note that link:http://www.grymoire.com/Unix/Awk.html[awk] version `4.0.1` is required for documentation generation.
 
 Documentation can be generated locally with:
@@ -138,8 +164,13 @@
 Java tests that require Python code will be skipped. Developers should also install link:https://pypi.python.org/pypi/pip[pip]
 and link:https://virtualenv.pypa.io/en/stable/[virtualenv] (version 15.0.2 - older versions may cause build failures).
 
-The build expects two Python executables `python` and `python3` where `python` maps to 2.7.6 and `python3` is 3.4.3 or
-higher. Once the Python environment is established, the full building and testing of `gremlin-python` may commence. It
+The build expects Python a `python3` installation which should be 3.5.3 or better. Python also tests kerberos and
+therefore requires:
+
+[source,text]
+sudo apt install libkrb5-dev krb5-user
+
+Once the Python environment is established, the full building and testing of `gremlin-python` may commence. It
 can be done manually from the command line with:
 
 [source,text]
@@ -149,10 +180,10 @@
 `gremlin-python` module which will signify to Maven that the environment is Python-ready. The `.glv` file need not have
 any contents and is ignored by Git. A standard `mvn clean install` will then build `gremlin-python` in full.
 
-As of TinkerPop 3.2.5, the build also requires Python to execute `gremlin-console` integration tests. The integration
-test is configured by a "console-integration-tests" Maven profile. This profile can be activated manually or can more
-simply piggy-back on the `.glv` file in `gremlin-python`. Note that unlike `gremlin-python` the tests are actually
-integration tests and therefore must be actively switched on with `-DskipIntegrationTests=false`:
+The build also requires Python to execute `gremlin-console` integration tests. The integration test is configured by a
+"console-integration-tests" Maven profile. This profile can be activated manually or can more simply piggy-back on
+the `.glv` file in `gremlin-python`. Note that unlike `gremlin-python` the tests are actually integration tests and
+therefore must be actively switched on with `-DskipIntegrationTests=false`:
 
 [source,text]
 mvn clean install -pl gremlin-console -DskipIntegrationTests=false
@@ -199,6 +230,12 @@
 using `com.github.eirslett:frontend-maven-plugin` plugin. This copy of the Node.js runtime will not affect any
 other existing Node.js runtime instances in your machine.
 
+To run the development and build scripts of `gremlint` and its corresponding web page `docs/gremlint`, Node.js and npm
+have to be installed. When generating or publishing the TinkerPop website, the `docs/gremlint` web page has to be
+built. Consequently, the scripts `bin/generate-home.sh` and `bin/publish-home.sh` require that Node.js and npm are
+installed. Version 5.2.0 or newer of npm is recommended, as it comes pre-bundled with npx which provides tooling to
+easily serve the generated website locally. This is covered in more detail in the <<site,Site>> section.
+
 TIP: For those who do not have a full Maven environment, please see <<docker-integration,this section>> for how Docker
 can be used to help run tests.
 
@@ -436,3 +473,20 @@
 `target/generated-test-sources` should be marked as "Generated Sources Root". If they are not setup that way by
 Intellij by default then simply right-click on them use the "Mark Directory with" option to make the appropriate
 selections.
+
+The `gremlin-grammar` module requires ANTLR processing. While this processing is configured to execute with Maven, it
+can also be setup to generate parser files within Intellij itself on command:
+
+. Install the ANTLR4 Grammar Plugin for Intellij
+. Right-click on the `Gremlin.g4` file and "Configure ANTLR"
+. Set "Output directory where all output is generated" to `target/generated-sources/antlr4`
+. Set "Grammar file encoding" to `utf-8`
+. Set "Package/namespace for the generated code" to `org.apache.tinkerpop.gremlin.language.grammar`
+. Set "Language" to `Java`
+. Set "Case transformation in the Preview window" should be "Leave as-is"
+. The "generate parse tree listener" should be unchecked and the "generate parse tree visitor" should be checked.
+
+With these settings it should be possible to right-click `Gremlin.g4` and "Generate ANTLR Recognizer" which will place
+the generated code in where specified at `target/generated-sources/antlr4`. Be sure to right-click the `antlr4`
+directory and "Mark directory as" "Generated Sources Root" which should allow Intellij to recognize it.
+
diff --git a/docs/src/dev/developer/for-committers.asciidoc b/docs/src/dev/developer/for-committers.asciidoc
index 5054a70..45d418e 100644
--- a/docs/src/dev/developer/for-committers.asciidoc
+++ b/docs/src/dev/developer/for-committers.asciidoc
@@ -232,7 +232,7 @@
 ** `get_g_V_groupCount_byXnameX()`
 ** `get_g_V_groupCountXaX_byXnameX_capXaX()`
 * The name of the actual test case should be the name of the traversal generator minus the `get_` prefix.
-* The Gremlin-Groovy version of the test should use the sugar syntax in order to test sugar (as Gremlin-Java8 tests test standard syntax).
+* The Gremlin-Groovy version of the test should use the sugar syntax in order to test sugar (as Gremlin-Java tests test standard syntax).
 ** `g.V.age.sum`
 * Avoid using lambdas in the test case unless that is explicitly what is being tested as OLAP systems will typically not be able to execute those tests.
 * `AbstractGremlinProcessTest` has various static methods to make writing a test case easy.
@@ -251,10 +251,10 @@
 ----
 Scenario: g_VX1X_unionXrepeatXoutX_timesX2X__outX_name
   Given the modern graph
-  And using the parameter v1Id defined as "v[marko].id"
+  And using the parameter vId1 defined as "v[marko].id"
   And the traversal of
     """
-    g.V(v1Id).union(__.repeat(__.out()).times(2), __.out()).values("name")
+    g.V(vId1).union(__.repeat(__.out()).times(2), __.out()).values("name")
     """
   When iterated to list
   Then the result should be unordered
@@ -317,10 +317,10 @@
 [source,gherkin]
 ----
 Given the modern graph
-And using the parameter v1Id defined as "v[marko].id"
+And using the parameter vId1 defined as "v[marko].id"
 ----
 
-In the above example, "v1Id" is the name of the parameter that will be used in the traversal. The end of that line in
+In the above example, "vId1" is the name of the parameter that will be used in the traversal. The end of that line in
 quotes is the value of that parameter and should use the type system notation that has been developed for the TinkerPop
 Gherkin tests. The type system notation ensures that different language variants have the ability to construct the
 appropriate types expected by the tests.
@@ -356,13 +356,26 @@
 include the `.id` suffix which would indicate getting the vertex identifier or the `.sid` suffix which gets a string
 representation of the edge identifier.
 
+In addition, parameter names should adhere to a common form as they hold some meaning to certain language variant
+implementations:
+
+* General variables of no particular type should use `xx1`, `xx2` and `xx3`.
+* A `Vertex` variable should be prefixed with "v" and be followed by the `id`, therefore, `v1` would signify a `Vertex`
+with the `id` of "1".
+* An `Edge` variable follows the pattern of vertices but with a "e" prefix.
+* The "id" of a `Vertex` or `Edge` is prefixed with "vid"`" or "eid" respectively followed by the `id`, thus, `vid1`
+would be "1" and refer to the `Vertex` with that `id`.
+* `Function` variables should use `l1` and `l2`.
+* `Predicate` variables should use `pred1`.
+* `Comparator` variables should use `c1` and `c2`.    
+
 Finally, specify the traversal under test with the "Given" option "and the traversal":
 
 [source,gherkin]
 ----
 And the traversal of
   """
-  g.V(v1Id).union(__.repeat(__.out()).times(2), __.out()).values("name")
+  g.V(vId1).union(__.repeat(__.out()).times(2), __.out()).values("name")
   """
 ----
 
@@ -660,9 +673,10 @@
 === Binary LICENSE and NOTICE
 
 The binary LICENSE/NOTICE is perhaps most impacted by changes to the various `pom.xml` files. After altering the
-`pom.xml` file of any module, build both Gremlin Console and Gremlin Server and examine the contents of the binary
-distributions:
+`pom.xml` file of any module, build `gremlin-driver`, Gremlin Console and Gremlin Server and examine the contents of
+the binary distributions:
 
+* target/gremlin-driver-x.y.z-uber.jar
 * target/gremlin-console-x.y.z-uber.jar
 * target/apache-tinkerpop-gremlin-console-x.y.z-distribution.zip
 * target/apache-tinkerpop-gremlin-server-x.y.z-distribution.zip
@@ -670,8 +684,8 @@
 Apache licensed software does not need to be included in LICENSE, but if the new dependency is an Apache-approved
 license (e.g. BSD, MIT) then it should be added in the pattern already defined. A copy of the LICENSE should be
 added to the `<project>/src/main/static/licenses` directory of the code repository and the `maven-shade-plugin` section
-of the `gremlin-console` `pom.xml` should be updated to reference this new license file so that it is included in the
-uber jar.
+of the `gremlin-console` and `gremlin-driver` `pom.xml` files should be updated to reference this new license file so
+that it is included in the uber jar.
 
 To determine if changes are required to the NOTICE, first check if the bundled jar has a NOTICE file in it (typically
 found in `/META-INF` directory of the jar).
@@ -704,6 +718,18 @@
 `<outputDirectory>` and `<imagesdir>`.  Note that the `<outputDirectory>` represents where the book will exist when
 uploaded to the server and should preserve the directory structure in git as referenced in `<sourceDirectory>`.
 
+Adding Gremlin code examples to any of the link:https://github.com/apache/tinkerpop/tree/master/docs/src/recipes[docs/src/recipes]
+or to link:https://github.com/apache/tinkerpop/tree/master/docs/src/reference/the-traversal.asciidoc[docs/src/reference/the-traversal.asciidoc]
+also has the effect of improving testing of the Gremlin language. All Gremlin found in code sections that are marked
+as `[gremlin-groovy]` are tested in two ways:
+
+1. When `mvn clean install` is executed all such Gremlin are passed through the grammar parser to ensure validity.
+As the grammar parser is not a Groovy parser, the test framework attempts to filter away or ignore things it can't
+possibly parse. Ideally, examples should be written in such a way as to be parsed by the grammar, but in cases where it
+cannot be as such, the test suite simply needs to be modified to suitably ignore the example.
+2. When the documentation is built, the code snippets are actually executed and errors will result in a failure to
+build the documentation.
+
 Please see the <<building-testing,Building and Testing>> section for more information on how to generate the
 documentation.
 
@@ -740,8 +766,13 @@
 The content for the TinkerPop home page and related pages that make up the web site at link://tinkerpop.apache.org[tinkerpop.apache.org]
 is stored in the git repository under `/docs/site`. In this way, it becomes easier for the community to provide content
 presented there, because the content can be accepted via the standard workflow of a pull request. To generate the site
-for local viewing, run `bin/generate-home.sh`, which will build the site in `target/site/`. PMC members can officially
-publish the site with `bin/publish-home.sh <username>`.
+for local viewing, run `bin/generate-home.sh`, which will build the site in `target/site/`. Note that Node.js and npm
+have to be installed in order for the script to work. See the <<nodejs-environment,JavaScript Environment>> section for
+more info about what parts of TinkerPop depend on Node.js and npm. While most of the generated website files can be
+viewed locally by opening them in a browser, some of them rely on imported resources that will be blocked by the
+browser's same-origin policy if not served from a single origin using a web server. The generated website can be served
+locally by running `npx serve target/site/home`. PMC members can officially publish the site with
+`bin/publish-home.sh <username>`.
 
 "Publishing" does not publish documentation (e.g. reference docs, javadocs, etc) and only publishes what is generated
 from the content in `/docs/site`. Publishing the site can be performed out of band with the release cycle and is no
diff --git a/docs/src/dev/developer/release.asciidoc b/docs/src/dev/developer/release.asciidoc
index 677e5f9..823d8c6 100644
--- a/docs/src/dev/developer/release.asciidoc
+++ b/docs/src/dev/developer/release.asciidoc
@@ -144,12 +144,18 @@
 . `docker/build.sh -t -i -n`
 . `bin/publish-docs.sh <username>` - note that under a release candidate the documentation is published as SNAPSHOT
 . `mvn versions:set -DnewVersion=xx.yy.zz -DgenerateBackupPoms=false` to update the project files to reference a non-SNAPSHOT version
+. `mvn clean install -DskipTests` to update GLV versions
+.. Review `Gremlin.Net.csproj`, `Gremlin.Net.Template.csproj` and `Gremlin.Net.Template.nuspec` in `gremlin-dotnet`
+.. Review `package.json` in `gremlin-javascript`
 . `pushd gremlin-console/bin; ln -fs ../target/apache-tinkerpop-gremlin-console-xx.yy.zz-standalone/bin/gremlin.sh gremlin.sh; popd`
 . `git diff` and review the updated files
 . `git commit -a -m "TinkerPop xx.yy.zz release"` and `git push`
 . `git tag -a -m "TinkerPop xx.yy.zz release" xx.yy.zz` and `git push --tags`
 . `mvn clean install`
 . `mvn versions:set -DnewVersion=xx.yy.zz-SNAPSHOT -DgenerateBackupPoms=false` to go back to SNAPSHOT
+. `mvn clean install -DskipTests` to update GLV versions
+.. Review `Gremlin.Net.csproj`, `Gremlin.Net.Template.csproj` and `Gremlin.Net.Template.nuspec` in `gremlin-dotnet`
+.. Review `package.json` in `gremlin-javascript`
 . `pushd gremlin-console/bin; ln -fs ../target/apache-tinkerpop-gremlin-console-xx.yy.zz-SNAPSHOT-standalone/bin/gremlin.sh gremlin.sh; popd`
 . `git commit -a -m "Returned to xx.yy.zz-SNAPSHOT"` and `git push`
 . Announce the release candidate to `dev` mailing list and await feedback
@@ -205,6 +211,9 @@
 as accurate as possible and the release tags are present).
 .. Preview changes locally with `bin/generate-home.sh` then commit changes to git.
 . `mvn versions:set -DnewVersion=xx.yy.zz -DgenerateBackupPoms=false` to update project files to reference the non-SNAPSHOT version
+. `mvn clean install -DskipTests` to update GLV versions
+.. Review `Gremlin.Net.csproj`, `Gremlin.Net.Template.csproj` and `Gremlin.Net.Template.nuspec` in `gremlin-dotnet`
+.. Review `package.json` in `gremlin-javascript`
 . `pushd gremlin-console/bin; ln -fs ../target/apache-tinkerpop-gremlin-console-xx.yy.zz-standalone/bin/gremlin.sh gremlin.sh; popd`
 . `git diff` and review the updated files
 . `mvn clean install` - need to build first so that the right version of the console is used with `bin/publish-docs.sh`
@@ -280,6 +289,9 @@
 . Prepare Git administration tasks. Apply the following steps as needed per release branch:
 .. Make the appropriate branching changes as required by the release and bump the version to `SNAPSHOT` with
 `mvn versions:set -DnewVersion=xx.yy.zz-SNAPSHOT -DgenerateBackupPoms=false`.
+. `mvn clean install -DskipTests` to update GLV versions
+.. Review `Gremlin.Net.csproj`, `Gremlin.Net.Template.csproj` and `Gremlin.Net.Template.nuspec` in `gremlin-dotnet`
+.. Review `package.json` in `gremlin-javascript`
 .. `pushd gremlin-console/bin; ln -fs ../target/apache-tinkerpop-gremlin-console-xx.yy.zz-SNAPSHOT-standalone/bin/gremlin.sh gremlin.sh; popd`
 .. Update CHANGELOG and upgrade docs to have the appropriate headers for the next version.
 .. `mvn clean install -DskipTests` - need to build first so that the right version of the console is used with `bin/publish-docs.sh`
diff --git a/docs/src/dev/io/gryo.asciidoc b/docs/src/dev/io/gryo.asciidoc
index e06fcc2..15bafd2 100644
--- a/docs/src/dev/io/gryo.asciidoc
+++ b/docs/src/dev/io/gryo.asciidoc
@@ -25,7 +25,7 @@
 import org.apache.tinkerpop.gremlin.structure.*
 import org.apache.tinkerpop.gremlin.structure.io.gryo.*
 import org.apache.tinkerpop.gremlin.structure.io.*
-import org.apache.commons.configuration.BaseConfiguration
+import org.apache.commons.configuration2.BaseConfiguration
 import java.time.*
 
 new File("io-output/dev-docs/").mkdirs()
@@ -157,7 +157,8 @@
 side, newer release of TinkerPop are fully backward compatible with Gryo produced on older versions of TinkerPop.
 
 As of TinkerPop 3.3.0, there is now a new version of Gryo in 3.0 that is only partially compatible with 1.0. Attempts
-to use 3.0 serializers with 1.0 serializers will likely lead to failure.
+to use 3.0 serializers with 1.0 serializers will likely lead to failure. For best results, users should always
+utilize the same version of TinkerPop on the client as on the server.
 
 Both versions of Gryo support all the types defined by GraphSON as well as others that are bound more specifically
 to the JVM. The link:https://github.com/apache/tinkerpop/blob/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java[GryoVersion]
diff --git a/docs/src/dev/provider/index.asciidoc b/docs/src/dev/provider/index.asciidoc
index 863a799..1c928f6 100644
--- a/docs/src/dev/provider/index.asciidoc
+++ b/docs/src/dev/provider/index.asciidoc
@@ -39,7 +39,7 @@
 [[graph-system-provider-requirements]]
 == Graph System Provider Requirements
 
-image:tinkerpop-enabled.png[width=140,float=left] At the core of TinkerPop 3.x is a Java8 API. The implementation of this
+image:tinkerpop-enabled.png[width=140,float=left] At the core of TinkerPop 3.x is a Java API. The implementation of this
 core API and its validation via the `gremlin-test` suite is all that is required of a graph system provider wishing to
 provide a TinkerPop-enabled graph engine. Once a graph system has a valid implementation, then all the applications
 provided by TinkerPop (e.g. Gremlin Console, Gremlin Server, etc.) and 3rd-party developers (e.g. Gremlin-Scala,
@@ -79,7 +79,7 @@
 `Graph.addVertex(Object...)` or `Vertex.addEdge(String,Vertex,Object...)`, the respective element is created along
 with the provided key/value pair properties appended to it.
 
-Below is a sequence of basic graph mutation operations represented in Java 8.
+Below is a sequence of basic graph mutation operations represented in Java:
 
 image:basic-mutation.png[width=240,float=right]
 [source,java]
@@ -932,14 +932,16 @@
 |204 |NO CONTENT |The server processed the request but there is no result to return (e.g. an `Iterator` with no elements) - there are no messages remaining in this stream.
 |206 |PARTIAL CONTENT |The server successfully returned some content, but there is more in the stream to arrive - wait for a `SUCCESS` to signify the end of the stream.
 |401 |UNAUTHORIZED |The request attempted to access resources that the requesting user did not have access to.
+|403 |FORBIDDEN |The server could authenticate the request, but will not fulfill it.
 |407 |AUTHENTICATE |A challenge from the server for the client to authenticate its request.
-|497 |CLIENT SERIALIZATION ERROR |The request message contained an object that was not serializable.
-|498 |MALFORMED REQUEST |The request message was not properly formatted which means it could not be parsed at all or the "op" code was not recognized such that Gremlin Server could properly route it for processing.  Check the message format and retry the request.
-|499 |INVALID REQUEST ARGUMENTS |The request message was parseable, but the arguments supplied in the message were in conflict or incomplete. Check the message format and retry the request.
+|497 |REQUEST ERROR SERIALIZATION |The request message contained an object that was not serializable.
+|498 |REQUEST ERROR MALFORMED REQUEST |The request message was not properly formatted which means it could not be parsed at all or the "op" code was not recognized such that Gremlin Server could properly route it for processing.  Check the message format and retry the request.
+|499 |REQUEST ERROR INVALID REQUEST ARGUMENTS |The request message was parseable, but the arguments supplied in the message were in conflict or incomplete. Check the message format and retry the request.
 |500 |SERVER ERROR |A general server error occurred that prevented the request from being processed.
-|597 |SCRIPT EVALUATION ERROR |The script submitted for processing evaluated in the `ScriptEngine` with errors and could not be processed.  Check the script submitted for syntax errors or other problems and then resubmit.
-|598 |SERVER TIMEOUT |The server exceeded one of the timeout settings for the request and could therefore only partially responded or did not respond at all.
-|599 |SERVER SERIALIZATION ERROR |The server was not capable of serializing an object that was returned from the script supplied on the request. Either transform the object into something Gremlin Server can process within the script or install mapper serialization classes to Gremlin Server.
+|596 |SERVER ERROR TEMPORARY |A server error occurred, but it was temporary in nature and therefore the client is free to retry it's request as-is with the potential for success.
+|597 |SERVER ERROR EVALUATION |The script submitted for processing evaluated in the `ScriptEngine` with errors and could not be processed.  Check the script submitted for syntax errors or other problems and then resubmit.
+|598 |SERVER ERROR TIMEOUT |The server exceeded one of the timeout settings for the request and could therefore only partially responded or did not respond at all.
+|599 |SERVER ERROR SERIALIZATION |The server was not capable of serializing an object that was returned from the script supplied on the request. Either transform the object into something Gremlin Server can process within the script or install mapper serialization classes to Gremlin Server.
 |=========================================================
 
 NOTE: Please refer to the link:https://tinkerpop.apache.org/docs/current/dev/io[IO Reference Documentation] for more
@@ -1023,14 +1025,13 @@
 !Key !Description
 !`authentication` !A request that contains the response to a server challenge for authentication.
 !`eval` !Evaluate a Gremlin script provided as a `String`.
-!`close` !Close the specified session. Will return a `NO CONTENT` message as confirmation of the close being completed.
 |=========================================================
 
-NOTE: The "close" message is deprecated as of 3.3.11 as servers at this version are required to automatically interrupt
-running processes on the close of the connection and release resources such as sessions. Servers wishing to be
-compatible with older versions of the driver need only send back a `NO_CONTENT` for this message. Drivers wishing to
-be compatible with servers prior to 3.3.11 may continue to send the message on calls to `close()` otherwise such code
-can be removed.
+NOTE: There was a "close" message related to sessions that was deprecated as of 3.3.11. It's functionality was removed
+in 3.5.0. Servers wishing to be compatible with older versions of the driver need only send back a `NO_CONTENT` for
+this message (which is what Gremlin Server does as of 3.5.0). Drivers wishing to be compatible with servers prior to
+3.3.11 may continue to send the message on calls to `close()` (TinkerPop drivers no longer do that as of 3.5.0)
+otherwise such code can be removed.
 
 **`authentication` operation arguments**
 
@@ -1075,13 +1076,13 @@
 
 Both the Standard and Session OpProcessors allow for Gremlin scripts to be submitted to the server. The
 `TraversalOpProcessor` however allows Gremlin `Bytecode` to be submitted to the server. Supporting this `OpProcessor`
-makes it possible for a link:https://tinkerpop.apache.org/docs/current/tutorials/gremlin-language-variants/[Gremlin Language Variant]
+makes it possible for a link:https://tinkerpop.apache.org/docs/x.y.z/reference/#gremlin-drivers-variants[Gremlin Language Variant]
 to submit a `Traversal` directly to Gremlin Server in the native language of the GLV without having to use a script in
 a different language.
 
 Unlike Standard and Session OpProcessors, the Traversal OpProcessor does not simply return the results of the
 `Traversal`. It instead returns `Traverser` objects which allows the client to take advantage of
-link:https://tinkerpop.apache.org/docs/current/reference/#barrier-step[bulking]. To describe this interaction more
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#barrier-step[bulking]. To describe this interaction more
 directly, the returned `Traverser` will represent some value from the `Traversal` result and the number of times it
 is represented in the full stream of results. So, if a `Traversal` happens to return the same vertex twenty times
 it won't return twenty instances of the same object. It will return one in `Traverser` with the `bulk` value set to
@@ -1112,14 +1113,6 @@
 unroll it to represent the actual number of times it exists when iterated. The unrolling is typically handled
 directly within TinkerPop's remote traversal implementations.
 
-One of the important aspects of the Traversal OpProcessor is that it enables the user to not only get the results of
-the `Traversal` but also the side-effects that it produces. When the `Traversal` is submitted with the "bytecode"
-operation, the results are iterated back as usual, but any side-effects are retained on the server in a cache keyed by
-the identifier of the request that originally submitted the `Traversal`. The client will want to retain that identifier
-if it intends to later get side-effects. The Traversal OpProcessor supplies the "keys" and "gather" operations to get
-the keys stored in the side-effect and to get the value of a specific side-effect respectively. Finally, a "close"
-operation is available to clear the cache of a specific side-effect.
-
 [width="100%",cols="3,10a",options="header"]
 |=========================================================
 |Key |Description
@@ -1130,9 +1123,6 @@
 !Key !Description
 !`authentication` !A request that contains the response to a server challenge for authentication.
 !`bytecode` !A request that contains the `Bytecode` representation of a `Traversal`.
-!`close` !Releases side-effects held in cache for a particular `Traversal`.
-!`gather` !Gets a particular side-effect as produced by a previously executed `Traversal`.
-!`keys` !Gets all the keys of all side-effects as produced by a previously executed `Traversal`.
 |=========================================================
 
 **`authentication` operation arguments**
@@ -1159,64 +1149,43 @@
 single alias).
 |=========================================================
 
-**`close` operation arguments**
-
-[width="100%",cols="2,2,9",options="header"]
-|=========================================================
-|Key |Type |Description
-|sideEffect |UUID | *Required* The unique identifier for the request that original submitted the traversal (side-effects are keyed by that value)
-|=========================================================
-
-**`gather` operation arguments**
-
-[width="100%",cols="2,2,9",options="header"]
-|=========================================================
-|Key |Type |Description
-|sideEffect |UUID | *Required* The unique identifier for the request that original submitted the traversal (side-effects are keyed by that value)
-|sideEffectKey |String | *Required* The key for a specific side-effect.
-|aliases |Map | *Required* A map with a single key/value pair that refers to a globally bound `TraversalSource` object
-to be aliased to different variable names for purposes of the current request.  The value represents the name of the
-global variable and its key represents the new binding name as it will be referenced in the Gremlin query.  For
-example, if the Gremlin Server defines two `TraversalSource` instances named `g1`, it would be possible
-to send an alias pair with key of "g" and value of "g1" and thus allow the script to refer to "g1" simply as "g". Note
-that unlike users of `alias` in other contexts, in this case, the key can *only* be set to "g" and there can be only
-one key value pair present (since only one `Traversal` is being submitted, there is no sense to having more than a
-single alias).
-|=========================================================
-
-When using "gather" it is important to note the metadata that is returned on the `ResponseMessage`. It returns both the
-"sideEffectKey" that was requested as well as a value keyed as "aggregateTo". The "aggregateTo" field describes how the
-streamed side-effect data should be treated on the client. It provides a hint as to whether or not the data should be
-rolled back up into a single object or simply left as-is. There are four values for "aggregateTo": `bulkset`, `list`,
-`map`, `set` and `none`.
-
-**`keys` operation arguments**
-
-[width="100%",cols="2,2,9",options="header"]
-|=========================================================
-|Key |Type |Description
-|sideEffect |UUID | *Required* The unique identifier for the request that original submitted the traversal (side-effects are keyed by that value)
-|=========================================================
-
-=== Authentication
+=== Authentication and Authorization
 
 Gremlin Server supports link:https://en.wikipedia.org/wiki/Simple_Authentication_and_Security_Layer[SASL-based]
 authentication.  A SASL implementation provides a series of challenges and responses that a driver must comply with
-in order to authenticate.  By default, Gremlin Server only supports the "PLAIN" SASL mechanism, which is a cleartext
-password system.  When authentication is enabled, an incoming request is intercepted before it is evaluated by the
-`ScriptEngine`.  The request is saved on the server and a `AUTHENTICATE` challenge response (status code `407`) is
-returned to the client.
+in order to authenticate.  Gremlin Server supports the "PLAIN" SASL mechanism, which is a cleartext
+password system, for all link:https://tinkerpop.apache.org/docs/x.y.z/reference/#gremlin-drivers-variants[Gremlin Language Variants].
+Other SASL mechanisms supported for selected clients are listed in the
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#security[security section of the Gremlin Server reference documentation].
 
-The client will detect the `AUTHENTICATE` and respond with an `authentication` for the `op` and an `arg` named `sasl`
-that contains the password.  The password should be either, an encoded sequence of UTF-8 bytes, delimited by 0
-(US-ASCII NUL), where the form is : `<NUL>username<NUL>password`, or a Base64 encoded string of the former (which
-in this instance would be `AHVzZXJuYW1lAHBhc3N3b3Jk`).  Should Gremlin Server be able to authenticate with the
-provided credentials, the server will return the results of the original request as it normally does without
-authentication.  If it cannot authenticate given the challenge response from the client, it will return `UNAUTHORIZED`
-(status code `401`).
+When authentication is enabled, an incoming request is intercepted before it is evaluated by the `ScriptEngine`.  The
+request is saved on the server and a `AUTHENTICATE` challenge response (status code `407`) is returned to the client.
+
+The client will detect the `AUTHENTICATE` and respond with an `authentication` for the `op` and an `arg` named `sasl`.
+In case of the "PLAIN" SASL mechanism the `arg` contains the password.  The password should be either, an encoded
+sequence of UTF-8 bytes, delimited by 0 (US-ASCII NUL), where the form is : `<NUL>username<NUL>password`, or a Base64
+encoded string of the former (which in this instance would be `AHVzZXJuYW1lAHBhc3N3b3Jk`).  Should Gremlin Server be
+able to authenticate with the provided credentials, the server will return the results of the original request as it
+normally does without authentication.  If it cannot authenticate given the challenge response from the client, it will
+return `UNAUTHORIZED` (status code `401`).
 
 NOTE: Gremlin Server does not support the "authorization identity" as described in link:https://tools.ietf.org/html/rfc4616[RFC4616].
 
+In addition to authenticating users at the start of a connection, Gremlin Server allows providers to authorize users on
+a per request basis. If
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#_configuring_2[a java class is configured] that implements the
+link:https://tinkerpop.apache.org/javadocs/x.y.z/full/org/apache/tinkerpop/gremlin/server/authz/Authorizer.html[Authorizer interface],
+Gremlin Server passes each request to this `Authorizer`. The `Authorizer` can deny authorization for the request by
+throwing an exception and Gremlin Server returns `UNAUTHORIZED` (status code `401`) to the client. The `Authorizer`
+authorizes the request by returning the original request or the request with some additional constraints. Gremlin Server
+proceeds with the returned request and on its turn returns the result of the request to the client. More details on
+implementing authorization can be found in the
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#security[reference documentation for Gremlin Server security].
+
+NOTE: While Gremlin Server supports this authorization feature it is not a feature that TinkerPop requires of graph
+providers as part of the agreement between client and server.
+
+
 [[gremlin-plugins]]
 == Gremlin Plugins
 
diff --git a/docs/src/index.asciidoc b/docs/src/index.asciidoc
index dcd22f9..baf1f5b 100644
--- a/docs/src/index.asciidoc
+++ b/docs/src/index.asciidoc
@@ -63,8 +63,6 @@
 Identifies and explains the component parts of a Gremlin traversal.
 ^|image:gremlin-chef.png[width=125] |link:https://tinkerpop.apache.org/docs/x.y.z/recipes/[Gremlin Recipes] +
 A collection of best practices and common traversal patterns for Gremlin.
-^|image:gremlin-house-of-mirrors-cropped.png[width=200] |link:https://tinkerpop.apache.org/docs/x.y.z/tutorials/gremlin-language-variants/[Gremlin Language Variants] +
-Instructs developers on the approach to building a Gremlin variant in their native programming language.
 |image:gremlin-lab-coat.png[width=200] |link:http://sql2gremlin.com/[Sql2Gremlin] +
 Learn Gremlin using typical patterns found when querying data with SQL. (*external*)
 ^|image:gremlin-standing.png[width=125] |link:https://academy.datastax.com/resources/getting-started-graph-databases[Getting Started with Graph Databases] +
@@ -108,5 +106,5 @@
 |image:tinkerpop-enabled.png[width=200] |link:https://tinkerpop.apache.org/docs/x.y.z/dev/provider/[Providers] +
 Documentation for providers who implement the TinkerPop interfaces, develop plugins or drivers, or provide other third-party libraries for TinkerPop.
 |image:gremlin-io2.png[width=200] |link:https://tinkerpop.apache.org/docs/x.y.z/dev/io/[IO Reference] +
-Reference Documentation for providers and users of the various IO formats that TinkerPop has: GraphML, GraphSON and Gryo.
+Reference Documentation for providers and users of the various IO formats that TinkerPop has: GraphML, GraphSON, GraphBinary and Gryo.
 |=========================================================
diff --git a/docs/src/recipes/anti-patterns.asciidoc b/docs/src/recipes/anti-patterns.asciidoc
index 0d8f644..1341f33 100644
--- a/docs/src/recipes/anti-patterns.asciidoc
+++ b/docs/src/recipes/anti-patterns.asciidoc
@@ -56,7 +56,7 @@
           from("p${relation.from}").
           to("p${relation.to}")
 } ; []
-traversalAsString = org.apache.tinkerpop.gremlin.process.traversal.translator.GroovyTranslator.of("g").translate(t.bytecode) ; []
+traversalAsString = org.apache.tinkerpop.gremlin.process.traversal.translator.GroovyTranslator.of("g").translate(t.bytecode).getScript() ; []
 [ "Traversal String Length": traversalAsString.length()
 , "Traversal Preview": traversalAsString.replaceFirst(/^(.{104}).*(.{64})$/, '$1 ... $2') ]
 ----
@@ -68,7 +68,7 @@
 
 [gremlin-groovy]
 ----
-g.withSideEffect("relations", relations).
+g.withSideEffect("rels", relations).
   inject(persons).sideEffect(
     unfold().
     addV("person").
@@ -78,7 +78,7 @@
     group("m").
       by(id).
       by(unfold())).
-  select("relations").unfold().as("r").
+  select("rels").unfold().as("r").
   addE("knows").
     from(select("m").select(select("r").select("from"))).
     to(select("m").select(select("r").select("to"))).
@@ -228,9 +228,12 @@
 [[steps-instead-of-tokens]]
 == Steps Instead of Tokens
 
-When child traversals contain a single step, there's a good chance that the step can be replaced with a token. These tokens are translated
-into optimized traversals that execute much faster then their step traversal pendants. A few examples of single step child traversals are
-shown in the following code block.
+NOTE: As of 3.5.0, `ByModulatorOptimizationStrategy` is present to automatically translate this anti-pattern to their
+more performant versions for most cases however, it is still best to write Gremlin according to the contents that follow.
+
+When child traversals contain a single step, there's a good chance that the step can be replaced with a token. These
+tokens are translated into optimized traversals that execute much faster then their step traversal pendants. A few
+examples of single step child traversals are shown in the following code block.
 
 [gremlin-groovy,modern]
 ----
@@ -260,33 +263,3 @@
 
 <1> Note, that tokens use a `fold()` reducer by default.
 <2> `by("name")` doesn't use a token, but falls into the same category as the String `"name"` is translated into an optimized traversal.
-
-But this is not all about readability; as initially mentioned, the use of tokens also improves the overall query performance as shown in
-the `profile()` output below.
-
-[gremlin-groovy,existing]
-----
-g.V().groupCount().by(label()).profile()               // not using token
-g.V().groupCount().by(label).profile()                 // using a token
-g.V().group().by(label()).by(id().fold()).profile()    // not using tokens
-g.V().group().by(label).by(id).profile()               // using tokens
-g.V().project("id","label").
-    by(id()).
-    by(label()).profile()                              // not using tokens
-g.V().project("id","label").
-    by(id).
-    by(label).profile()                                // using tokens
-g.V().choose(label()).
-    option("person", project("person").by(values("name"))).
-    option("software", project("product").by(values("name"))).
-  profile()                                            // not using tokens
-g.V().choose(label).
-    option("person", project("person").by("name")).
-    option("software", project("product").by("name")).
-  profile()                                            // using tokens
-----
-
-NOTE: Pay attention to all metrics. The time difference does not always look significant, sometimes it might even be worse in the
-optimized query, but that's usually because TinkerGraph keeps everything in memory and thus even bad queries can sometimes perform
-surprisingly well. The more important metrics, however, are the number of traversers that are used and the overall number of
-generated steps.
diff --git a/docs/src/recipes/centrality.asciidoc b/docs/src/recipes/centrality.asciidoc
index c5e19a2..d75dbc6 100644
--- a/docs/src/recipes/centrality.asciidoc
+++ b/docs/src/recipes/centrality.asciidoc
@@ -103,7 +103,7 @@
 
 WARNING: Since the betweeness centrality algorithm requires the shortest path between any pair of vertices in the graph,
 its practical applications are very limited. It's recommended to use this algorithm only on small subgraphs (graphs like
-the link:https://tinkerpop.apache.org/docs/current/reference/#grateful-dead[Grateful Dead graph] with only 808 vertices
+the link:https://tinkerpop.apache.org/docs/x.y.z/reference/#grateful-dead[Grateful Dead graph] with only 808 vertices
 and 8049 edges already require a massive amount of compute resources to determine the shortest paths between all vertex
 pairs).
 
@@ -141,7 +141,7 @@
 
 WARNING: Since the closeness centrality algorithm requires the shortest path between any pair of vertices in the graph,
 its practical applications are very limited. It's recommended to use this algorithm only on small subgraphs (graphs like
-the link:https://tinkerpop.apache.org/docs/current/reference/#grateful-dead[Grateful Dead graph] with only 808 vertices
+the link:https://tinkerpop.apache.org/docs/x.y.z/reference/#grateful-dead[Grateful Dead graph] with only 808 vertices
 and 8049 edges already require a massive amount of compute resources to determine the shortest paths between all vertex
 pairs).
 
@@ -168,7 +168,7 @@
 time to converge on a solution. Calling `cap('m')` at the end simply extracts the `Map` side-effect stored in "m".
 <2> The entries in the `Map` are then iterated and sorted with the top ten most central vertices presented as output.
 <3> The previous examples can be expanded on a little bit by including a
-link:https://tinkerpop.apache.org/docs/current/reference/#timelimit-step[time limit]. The `timeLimit()` prevents the
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#timelimit-step[time limit]. The `timeLimit()` prevents the
 traversal from taking longer than one hundred milliseconds to execute (the previous example takes considerably longer
 than that). While the answer provided with the `timeLimit()` is not the absolute ranking, it does provide a relative
 ranking that closely matches the absolute one. The use of `timeLimit()` in certain algorithms (e.g. recommendations)
@@ -185,5 +185,5 @@
 [gremlin-groovy,modern]
 ----
 g = traversal().withEmbedded(graph).withComputer()
-g.V().pageRank().by('pageRank').values('pageRank')
+g.V().pageRank().with(PageRank.propertyName,'pageRank').values('pageRank')
 ----
diff --git a/docs/src/recipes/collections.asciidoc b/docs/src/recipes/collections.asciidoc
index 9ab74ea..9efda1b 100644
--- a/docs/src/recipes/collections.asciidoc
+++ b/docs/src/recipes/collections.asciidoc
@@ -22,7 +22,7 @@
 Lists and maps form the basis for much of the processing in Gremlin traversals. They are core to how side-effects
 are typically held and how results are generally produced. Being able to pick them apart and reformat them is sometimes
 required. This need to shape the data within a traversal may arise both at the
-link:https://tinkerpop.apache.org/docs/current/reference/#terminal-steps[terminal step] of the traversal (technically
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#terminal-steps[terminal step] of the traversal (technically
 just prior to the terminal step) or in the middle of a traversal. Considering the former, a transformation just prior
 to iteration will get the result into the form required by the application which would remove the need for additional
 application level manipulation. Moreover, a transformation at this stage may reduce the size of the payload being
diff --git a/docs/src/recipes/looping.asciidoc b/docs/src/recipes/looping.asciidoc
index 164bfd9..3ae4ecc 100644
--- a/docs/src/recipes/looping.asciidoc
+++ b/docs/src/recipes/looping.asciidoc
@@ -82,8 +82,8 @@
 ----
 g.withSack(1).V('A').
   repeat(both().simplePath().
-    sack(assign).by(loops())
-  ).emit().
+         sack(assign).by(loops())).
+    emit().
   project('vertex', 'depth').
     by().
     by(sack())
@@ -95,9 +95,11 @@
 [gremlin-groovy,existing]
 ----
 g.V('A').
-  repeat(both().simplePath().group('x').
-    by(loops())
-  ).emit().times(3).
+  repeat(both().simplePath().
+         group('x').
+           by(loops())).
+    emit().
+    times(3).
   cap('x')
 ----
 
diff --git a/docs/src/recipes/olap-spark-yarn.asciidoc b/docs/src/recipes/olap-spark-yarn.asciidoc
index f5e8558..64cc6a0 100644
--- a/docs/src/recipes/olap-spark-yarn.asciidoc
+++ b/docs/src/recipes/olap-spark-yarn.asciidoc
@@ -63,8 +63,8 @@
 #!/bin/bash
 # Variables to be adapted to the actual environment
 GREMLIN_HOME=/home/yourdir/lib/apache-tinkerpop-gremlin-console-x.y.z-standalone
-export HADOOP_HOME=/usr/local/lib/hadoop-2.7.2
-export HADOOP_CONF_DIR=/usr/local/lib/hadoop-2.7.2/etc/hadoop
+export HADOOP_HOME=/usr/local/lib/hadoop-2.7.7
+export HADOOP_CONF_DIR=/usr/local/lib/hadoop-2.7.7/etc/hadoop
 
 # Have TinkerPop find the hadoop cluster configs and hadoop native libraries
 export CLASSPATH=$HADOOP_CONF_DIR
@@ -94,7 +94,7 @@
 archive = 'spark-gremlin.zip'
 archivePath = "/tmp/$archive"
 ['bash', '-c', "rm -f $archivePath; cd ext/spark-gremlin/lib && zip $archivePath *.jar"].execute().waitFor()
-conf = new PropertiesConfiguration('conf/hadoop/hadoop-gryo.properties')
+conf = new Configurations().properties(new File('conf/hadoop/hadoop-gryo.properties'))
 conf.setProperty('spark.master', 'yarn')
 conf.setProperty('spark.submit.deployMode', 'client')
 conf.setProperty('spark.yarn.archive', "$archivePath")
diff --git a/docs/src/recipes/recommendation.asciidoc b/docs/src/recipes/recommendation.asciidoc
index d16f7ee..f02c4e9 100644
--- a/docs/src/recipes/recommendation.asciidoc
+++ b/docs/src/recipes/recommendation.asciidoc
@@ -33,7 +33,7 @@
   addV("person").property("name","bob").
   addV("person").property("name","jon").
   addV("person").property("name","jack").
-  addV("person").property("name","jill")iterate()
+  addV("person").property("name","jill").iterate()
 (1..10).each {
   g.addV("product").property("name","product #${it}").iterate()
 }; []
@@ -269,7 +269,7 @@
 Gremlin provides a number of steps that can help with these limits like:
 link:https://tinkerpop.apache.org/docs/x.y.z/reference/#coin-step[coin()],
 link:https://tinkerpop.apache.org/docs/x.y.z/reference/#sample-step[sample()], and
-link:https://tinkerpop.apache.org/docs/current/reference/#timelimit-step[timeLimit()]. For example, to have the
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#timelimit-step[timeLimit()]. For example, to have the
 traversal sample the data for no longer than one second, the previous "basic" recommendation could be changed to:
 
 [gremlin-groovy,existing]
diff --git a/docs/src/recipes/traversal-induced-values.asciidoc b/docs/src/recipes/traversal-induced-values.asciidoc
index f3592b8..6e421dd 100644
--- a/docs/src/recipes/traversal-induced-values.asciidoc
+++ b/docs/src/recipes/traversal-induced-values.asciidoc
@@ -33,8 +33,8 @@
 
 [gremlin-groovy,modern]
 ----
-marko = g.V().has('name','marko').next()
-g.V(marko).out('knows').has('age', gt(marko.value('age'))).values('name')
+vMarko = g.V().has('name','marko').next()
+g.V(vMarko).out('knows').has('age', gt(marko.value('age'))).values('name')
 ----
 
 The downside to this approach is that it takes two separate traversals to answer the question. Ideally, there should
@@ -137,9 +137,9 @@
   addV('tank').property('name', 'c').property('amount', 0.0).as('c').
   addE('drain').property('factor', 0.5).from('a').to('b').
   addE('drain').property('factor', 0.1).from('b').to('c').iterate()
-a = g.V().has('name','a').next()
-g.withSack(a.value('amount')).
-  V(a).repeat(outE('drain').sack(mult).by('factor').
+vA = g.V().has('name','a').next()
+g.withSack(vA.value('amount')).
+  V(vA).repeat(outE('drain').sack(mult).by('factor').
               inV().property('amount', sack())).
        until(__.outE('drain').count().is(0)).iterate()
 g.V().elementMap()
diff --git a/docs/src/reference/gremlin-applications.asciidoc b/docs/src/reference/gremlin-applications.asciidoc
index d847140..29a568b 100644
--- a/docs/src/reference/gremlin-applications.asciidoc
+++ b/docs/src/reference/gremlin-applications.asciidoc
@@ -494,15 +494,10 @@
 [INFO] OpLoader - Adding the standard OpProcessor.
 [INFO] OpLoader - Adding the session OpProcessor.
 [INFO] OpLoader - Adding the traversal OpProcessor.
-[INFO] TraversalOpProcessor - Initialized cache for TraversalOpProcessor with size 1000 and expiration time of 600000 ms
 [INFO] GremlinServer - Executing start up LifeCycleHook
 [INFO] Logger$info - Loading 'modern' graph data.
 [INFO] GremlinServer - idleConnectionTimeout was set to 0 which resolves to 0 seconds when configuring this value - this feature will be disabled
 [INFO] GremlinServer - keepAliveInterval was set to 0 which resolves to 0 seconds when configuring this value - this feature will be disabled
-[WARN] AbstractChannelizer - The org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0 serialization class is deprecated.
-[INFO] AbstractChannelizer - Configured application/vnd.gremlin-v3.0+gryo with org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0
-[WARN] AbstractChannelizer - The org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0 serialization class is deprecated.
-[INFO] AbstractChannelizer - Configured application/vnd.gremlin-v3.0+gryo-stringd with org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0
 [INFO] AbstractChannelizer - Configured application/vnd.gremlin-v3.0+json with org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV3d0
 [INFO] AbstractChannelizer - Configured application/json with org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV3d0
 [INFO] AbstractChannelizer - Configured application/vnd.graphbinary-v1.0 with org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1
@@ -837,6 +832,10 @@
 [source,yaml]
 channelizer: org.apache.tinkerpop.gremlin.server.channel.WsAndHttpChannelizer
 
+NOTE: The `UnifiedChannelizer` introduced in 3.5.0 can also be used to support HTTP requests as its functionality
+is similar to `WsAndHttpChannelizer`. Please see the Gremlin Server UnifiedChannelizer Section of the Upgrade
+Documentation for 3.5.0 for more link:https://tinkerpop.apache.org/docs/current/upgrade/#_tinkerpop_3_5_0[details].
+
 The `HttpChannelizer` is already configured in the `gremlin-server-rest-modern.yaml` file that is packaged with the Gremlin
 Server distribution.  To utilize it, start Gremlin Server as follows:
 
@@ -965,10 +964,13 @@
 |Key |Description |Default
 |authentication.authenticator |The fully qualified classname of an `Authenticator` implementation to use.  If this setting is not present, then authentication is effectively disabled. |`AllowAllAuthenticator`
 |authentication.authenticationHandler | The fully qualified classname of an `AbstractAuthenticationHandler` implementation to use. If this setting is not present, but the `authentication.authenticator` is, it will use that authenticator with the default `AbstractAuthenticationHandler` implementation for the specified `Channelizer` |_none_
-|authentication.config |A `Map` of configuration settings to be passes to the `Authenticator` when it is constructed.  The settings available are dependent on the implementation. |_none_
-|authentication.enableAuditLog |The available authenticators can issue audit logging messages, binding the authenticated user to his remote socket address and binding requests with a gremlin query to the remote socket address. For privacy reasons, the default value of this setting is false. The audit logging messages are logged at the INFO level via the `audit.org.apache.tinkerpop.gremlin.server` logger, which can be configured using the log4j.properties file. |false
+|authentication.config |A `Map` of configuration settings to be passed to the `Authenticator` when it is constructed.  The settings available are dependent on the implementation. |_none_
+|authentication.enableAuditLog |Deprecated: replaced by `enableAuditLog` with slight changes in the log message format. |_false_
+|authorization.authorizer |The fully qualified classname of an `Authorizer` implementation to use. |_none_
+|authorization.config |A `Map` of configuration settings to be passed to the `Authorizer` when it is constructed.  The settings available are dependent on the implementation. |_none_
 |channelizer |The fully qualified classname of the `Channelizer` implementation to use.  A `Channelizer` is a "channel initializer" which Gremlin Server uses to define the type of processing pipeline to use.  By allowing different `Channelizer` implementations, Gremlin Server can support different communication protocols (e.g. WebSocket). |`WebSocketChannelizer`
-|graphManager |The fully qualified classname of the `GraphManager` implementation to use.  A `GraphManager` is a class that adheres to the TinkerPop `GraphManager` interface, allowing custom implementations for storing and managing graph references, as well as defining custom methods to open and close graphs instantiations. It is important to note that the TinkerPop HTTP and WebSocketChannelizers auto-commit and auto-rollback based on the graphs stored in the graphManager upon script execution completion. To prevent Gremlin Server from starting when all graphs fails, the `CheckedGraphManager` can be used.|`DefaultGraphManager`
+|enableAuditLog |The `AuthenticationHandler`, `AuthorizationHandler` and processors can issue audit logging messages with the authenticated user, remote socket address and requests with a gremlin query. For privacy reasons, the default value of this setting is false. The audit logging messages are logged at the INFO level via the `audit.org.apache.tinkerpop.gremlin.server` logger, which can be configured using the log4j.properties file. |_false_
+|graphManager |The fully qualified classname of the `GraphManager` implementation to use.  A `GraphManager` is a class that adheres to the TinkerPop `GraphManager` interface, allowing custom implementations for storing and managing graph references, as well as defining custom methods to open and close graphs instantiations. To prevent Gremlin Server from starting when all graphs fails, the `CheckedGraphManager` can be used.|`DefaultGraphManager`
 |graphs |A `Map` of `Graph` configuration files where the key of the `Map` becomes the name to which the `Graph` will be bound and the value is the file name of a `Graph` configuration file. |_none_
 |gremlinPool |The number of "Gremlin" threads available to execute actual scripts in a `ScriptEngine`. This pool represents the workers available to handle blocking operations in Gremlin Server. When set to `0`, Gremlin Server will use the value provided by `Runtime.availableProcessors()`. |0
 |host |The name of the host to bind the server to. |localhost
@@ -979,6 +981,9 @@
 |maxContentLength |The maximum length of the aggregated content for a message.  Works in concert with `maxChunkSize` where chunked requests are accumulated back into a single message.  A request exceeding this size will return a `413 - Request Entity Too Large` status code.  A response exceeding this size will raise an internal exception. |65536
 |maxHeaderSize |The maximum length of all headers. |8192
 |maxInitialLineLength |The maximum length of the initial line (e.g.  "GET / HTTP/1.0") processed in a request, which essentially controls the maximum length of the submitted URI. |4096
+|maxParameters |The maximum number of parameters that can be passed on a request. Larger numbers may impact performance for scripts. This configuration only applies to the `UnifiedChannelizer`. |16
+|maxSessionTaskQueueSize |The maximum size that an individual session can queue requests before starting to reject them. This configuration only applies to the `UnifiedChannelizer`. |4096
+|maxWorkQueueSize |The maximum size the general processing queue can grow before the `gremlinPool` starts to reject requests. |8192
 |metrics.consoleReporter.enabled |Turns on console reporting of metrics. |false
 |metrics.consoleReporter.interval |Time in milliseconds between reports of metrics to console. |180000
 |metrics.csvReporter.enabled |Turns on CSV reporting of metrics. |false
@@ -1007,10 +1012,11 @@
 |scriptEngines.<name>.staticImports |A comma separated list of "static" imports to make available to the `ScriptEngine`. |_none_
 |scriptEngines.<name>.scripts |A comma separated list of script files to execute on `ScriptEngine` initialization. `Graph` and `TraversalSource` instance references produced from scripts will be stored globally in Gremlin Server, therefore it is possible to use initialization scripts to add Traversal Strategies or create entirely new `Graph` instances all together. Instantiating a `LifeCycleHook` in a script provides a way to execute scripts when Gremlin Server starts and stops.|_none_
 |scriptEngines.<name>.config |A `Map` of configuration settings for the `ScriptEngine`.  These settings are dependent on the `ScriptEngine` implementation being used. |_none_
-|evaluationTimeout |The amount of time in milliseconds before a script evaluation and iteration of result times out. This feature can be turned off by setting the value to `0`. |30000
-|serializers |A `List` of `Map` settings, where each `Map` represents a `MessageSerializer` implementation to use along with its configuration. If this value is not set, then Gremlin Server will configure with GraphSON and Gryo but will not register any `ioRegistries` for configured graphs. |_empty_
+|evaluationTimeout |The amount of time in milliseconds before a request evaluation and iteration of result times out. This feature can be turned off by setting the value to `0`. |30000
+|serializers |A `List` of `Map` settings, where each `Map` represents a `MessageSerializer` implementation to use along with its configuration. If this value is not set, then Gremlin Server will configure with GraphSON and GraphBinary but will not register any `ioRegistries` for configured graphs. |_empty_
 |serializers[X].className |The full class name of the `MessageSerializer` implementation. |_none_
 |serializers[X].config |A `Map` containing `MessageSerializer` specific configurations. |_none_
+|sessionLifetimeTimeout |The maximum time in milliseconds that a session can exist. This value cannot be extended beyond this value irrespective of the number of requests and their individual timeouts. The session life cannot be extended once started. This configuration only applies to the `UnifiedChannelizer`. |600000 (10 minutes)
 |ssl.enabled |Determines if SSL is turned on or not. |false
 |ssl.keyStore |The private key in JKS or PKCS#12 format.  |_none_
 |ssl.keyStorePassword |The password of the `keyStore` if it is password-protected. |_none_
@@ -1023,7 +1029,9 @@
 |strictTransactionManagement |Set to `true` to require `aliases` to be submitted on every requests, where the `aliases` become the scope of transaction management. |false
 |threadPoolBoss |The number of threads available to Gremlin Server for accepting connections. Should always be set to `1`. |1
 |threadPoolWorker |The number of threads available to Gremlin Server for processing non-blocking reads and writes. |1
-|useEpollEventLoop |try to use epoll event loops (works only on Linux os) instead of netty NIO. |false
+|useCommonEngineForSessions |Ensures that the same `ScriptEngine` is used to support sessions and sessionless requests which will lead to better performance. Do not change this setting from the default without a specific use case in mind. This configuration only applies to the `UnifiedChannelizer`. |true
+|useEpollEventLoop |Try to use epoll event loops (works only on Linux os) instead of netty NIO. |false
+|useGlobalFunctionCacheForSessions |Enable the global function cache for sessions when using the `UnifiedChannelizer`. When `true` it means that functions created in one request to a session remain available on the next request to that session. This setting is only relevant when `useGlobalFunctionCacheForSessions` is `false`. |true
 |writeBufferHighWaterMark | If the number of bytes in the network send buffer exceeds this value then the channel is no longer writeable, accepting no additional writes until buffer is drained and the `writeBufferLowWaterMark` is met. |65536
 |writeBufferLowWaterMark | Once the number of bytes queued in the network send buffer exceeds the `writeBufferHighWaterMark`, the channel will not become writeable again until the buffer is drained and it drops below this value. |65536
 |=========================================================
@@ -1033,6 +1041,9 @@
 [[opprocessor-configurations]]
 ==== OpProcessor Configurations
 
+IMPORTANT: The `UnifiedChannelizer` does not rely on `OpProcessor` infrastructure. If using that channelizer, these
+configuration options can be ignored.
+
 An `OpProcessor` provides a way to plug-in handlers to Gremlin Server's processing flow. Gremlin Server uses this
 plug-in system itself to expose the packaged functionality that it exposes. Configurations can be supplied to an
 `OpProcessor` through the `processors` key in the Gremlin Server configuration file. Each `OpProcessor` can take a
@@ -1075,23 +1086,221 @@
 ===== TraversalOpProcessor
 
 The `TraversalOpProcessor` provides a way to accept traversals configured via <<connecting-via-drivers,withRemote()>>.
+It has no special configuration settings.
+
+==== Serialization
+
+Gremlin Server can accept requests and return results using different serialization formats. Serializers implement the
+`MessageSerializer` interface. In doing so, they express the list of mime types they expect to support. When
+configuring multiple serializers it is possible for two or more serializers to support the same mime type. Such a
+situation may be common with a generic mime type such as `application/json`. Serializers are added in the order that
+they are encountered in the configuration file and the first one added for a specific mime type will not be overridden
+by other serializers that also support it.
+
+The format of the serialization is configured by the `serializers` setting described in the table above.  Note that
+some serializers have additional configuration options as defined by the `serializers[X].config` setting.  The
+`config` setting is a `Map` where the keys and values get passed to the serializer at its initialization.  The
+available and/or expected keys are dependent on the serializer being used.  Gremlin Server comes packaged with three
+different serializers: GraphSON, Gryo, and GraphBinary (however, GraphSON and GraphBinary are the only two configured
+by default).
+
+===== GraphSON
+
+The GraphSON serializer produces human readable output in JSON format and is a good configuration choice for those
+trying to use TinkerPop from non-JVM languages.  JSON obviously has wide support across virtually all major
+programming languages and can be consumed by a wide variety of tools. The format itself is described in the
+link:https://tinkerpop.apache.org/docs/current/dev/io/#graphson[IO Documentation].
+
+[source,yaml]
+----
+  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV1d0 }
+  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV2d0 }
+----
+
+The above configuration represents the default serialization under the `application/json` MIME type and produces JSON
+consistent with standard JSON data types.  It has the following configuration option:
 
 [width="100%",cols="3,10,^2",options="header"]
 |=========================================================
-|Name |Description |Default
-|cacheExpirationTime |Time in milliseconds before side-effects from a `Traversal` will be evicted. |60000
-|cacheMaxSize |The maximum number of entries in the side-effect cache. |1000
+|Key |Description |Default
+|ioRegistries |A list of `IoRegistry` implementations to be applied to the serializer. |_none_
 |=========================================================
 
-If there is no intention to gather side-effects from traversals, the `cacheMaxSize` can be set to zero to disable the
-cache.
+[source,yaml]
+  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV1d0 }
+
+When the standard JSON data types are not enough (e.g. need to identify the difference between `double` and `float`
+data types), the above configuration will embed types into the JSON itself.  The type embedding uses standard Java
+type names, so interpretation from non-JVM languages will be required.  It has the MIME type of
+`application/vnd.gremlin-v1.0+json` and the following configuration options:
+
+[width="100%",cols="3,10,^2",options="header"]
+|=========================================================
+|Key |Description |Default
+|ioRegistries |A list of `IoRegistry` implementations to be applied to the serializer. |_none_
+|=========================================================
+
+===== Gryo
+
+WARNING: Gryo is no longer the recommended serialization format for Gremlin Server. Consider using
+<<server-graphbinary, GraphBinary>> instead.
+
+The Gryo serializer utilizes Kryo-based serialization which produces a binary output.  This format is best consumed
+by JVM-based languages. The format itself is described in the
+link:https://tinkerpop.apache.org/docs/current/dev/io/#gryo[IO Documentation].
+
+[source,yaml]
+  - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerGremlinV3d0 }
+
+It has the MIME type of `application/vnd.gremlin-v3.0+gryo` and the following configuration options:
+
+[width="100%",cols="3,10,^2",options="header"]
+|=========================================================
+|Key |Description |Default
+|bufferSize |The maximum size of the Kryo buffer for use on a single object being serialized.  Increasing this value will correct `KryoException` errors that complain of "Buffer too small". |_4096_
+|classResolverSupplier |The fully qualified classname of a custom `Supplier<ClassResolver>` which will be used when constructing `Kryo` instances. There is no direct default for this setting, but without a setting the `GryoClassResolver` is used. |_none_
+|custom |A list of classes with custom kryo `Serializer` implementations related to them in the form of `<class>;<serializer-class>`. |_none_
+|ioRegistries |A list of `IoRegistry` implementations to be applied to the serializer. |_none_
+|serializeResultToString |When set to `true`, results are serialized by first calling `toString()` on each object in the result list resulting in an extended MIME Type of `application/vnd.gremlin-v1.0+gryo-stringd`.  When set to `false` Kryo-based serialization is applied. |_false_
+|=========================================================
+
+As described above, there are multiple ways in which to register serializers for Kryo-based serialization.  Note
+that the `ioRegistries` setting is applied first, followed by the `custom` setting.
+
+Those configuring or implementing a `Supplier<ClassResolver>` should consider this an "advanced" option and typically
+important to use cases where server types need to be coerced to client types (i.e. a type is available on the server
+but not on the client).  Implementations should typically instantiate `ClassResolver` implementations that are
+extensions of the `GryoClassResolver` as this class is important to most serialization tasks in TinkerPop.
+
+[[server-graphbinary]]
+===== GraphBinary
+
+GraphBinary is a binary serialization format suitable for object trees, designed to reduce serialization overhead on
+both the client and the server, as well as limiting the size of the payload that is transmitted over the wire. The
+format itself is described in the link:https://tinkerpop.apache.org/docs/current/dev/io/#graphbinary[IO Documentation].
+
+[source,yaml]
+  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1 }
+
+It has the MIME type of `application/vnd.graphbinary-v1.0` and the following configuration options:
+
+[width="100%",cols="3,10,^2",options="header"]
+|=========================================================
+|Key |Description |Default
+|custom |A list of classes with custom kryo `Serializer` implementations related to them in the form of `<class>;<serializer-class>`. |_none_
+|ioRegistries |A list of `IoRegistry` implementations to be applied to the serializer. |_none_
+|builder |Name of the `TypeSerializerRegistry.Builder` instance to be used to construct the `TypeSerializerRegistry`. |_none_
+|=========================================================
+
+As described above, there are multiple ways in which to register serializers for GraphBinary-based serialization. Note
+that the `ioRegistries` setting is applied first, followed by the `custom` setting.
+
+[[metrics]]
+==== Metrics
+
+Gremlin Server produces metrics about its operations that can yield some insight into how it is performing. These
+metrics are exposed in a variety of ways:
+
+* Directly to the console where Gremlin Server is running
+* CSV file
+* link:http://ganglia.info/[Ganglia]
+* link:http://graphite.wikidot.com/[Graphite]
+* link:http://www.slf4j.org/[SLF4j]
+* link:https://en.wikipedia.org/wiki/Java_Management_Extensions[JMX]
+
+The configuration of each of these outputs is described in the Gremlin Server <<_configuring_2, Configuring>> section.
+Note that Graphite and Ganglia are not included as part of the Gremlin Server distribution and must be installed
+to the server manually.
+
+[source,text]
+----
+bin/gremlin-server.sh install com.codahale.metrics metrics-ganglia 3.0.2
+bin/gremlin-server.sh install com.codahale.metrics metrics-graphite 3.0.2
+----
+
+WARNING: Gremlin Server is built to work with Metrics 3.0.2. Usage of other versions may lead to unexpected problems.
+
+NOTE: Installing Ganglia will include `org.acplt:oncrpc`, which is an LGPL licensed dependency.
+
+Regardless of the output, the metrics gathered are the same. Each metric is prefixed with
+`org.apache.tinkerpop.gremlin.server.GremlinServer` and the following metrics are reported:
+
+* `sessions` - The number of sessions open at the time the metric was last measured. For the `UnifiedChannelizer`, each
+request creates a "session", even a so-called "sessionless request", which is basically a session that will only
+execute within the context of that single request.
+* `errors` - The number of total errors, mean rate, as well as the 1, 5, and 15-minute error rates.
+* `op.eval` - The number of script evaluations, mean rate, 1, 5, and 15 minute rates, minimum, maximum, median, mean,
+and standard deviation evaluation times, as well as the 75th, 95th, 98th, 99th and 99.9th percentile evaluation times
+(note that these time apply to both sessionless and in-session requests).
+* `op.traversal` - The number of `Traversal` bytecode-based executions, mean rate, 1, 5, and 15 minute rates, minimum,
+maximum, median, mean, and standard deviation evaluation times, as well as the 75th, 95th, 98th, 99th and 99.9th
+percentile evaluation times.
+* `engine-name.session.session-id.*` - Metrics related to different `GremlinScriptEngine` instances configured for
+session-based requests where "engine-name" will be the actual name of the engine, such as "gremlin-groovy" and
+"session-id" will be the identifier for the session itself. This metric is not measured under the `UnifiedChannelizer`.
+* `engine-name.sessionless.*` - Metrics related to different `GremlinScriptEngine` instances configured for sessionless
+requests where "engine-name" will be the actual name of the engine, such as "gremlin-groovy". This metric is not
+measured under the `UnifiedChannelizer`.
+
+==== As A Service
+
+Gremlin server can be configured to run as a service.
+
+===== Init.d (SysV)
+
+Link `bin/gremlin-server.sh` to `init.d`
+Be sure to set RUNAS to the service user in `bin/gremlin-server.conf`
+
+[source,bash]
+----
+# Install
+ln -s /path/to/apache-tinkerpop-gremlin-server-x.y.z/bin/gremlin-server.sh /etc/init.d/gremlin-server
+
+# Systems with chkconfig/service. E.g. Fedora, Red Hat
+chkconfig --add gremlin-server
+
+# Start
+service gremlin-server start
+
+# Or call directly
+/etc/init.d/gremlin-server restart
+
+----
+
+===== Systemd
+
+To install, copy the service template below to /etc/systemd/system/gremlin.service
+and update the paths `/path/to/apache-tinkerpop-gremlin-server` with the actual install path of Gremlin Server.
+
+[source,bash]
+----
+[Unit]
+Description=Apache TinkerPop Gremlin Server daemon
+Documentation=https://tinkerpop.apache.org/
+After=network.target
+
+[Service]
+Type=forking
+ExecStart=/path/to/apache-tinkerpop-gremlin-server/bin/gremlin-server.sh start
+ExecStop=/path/to/apache-tinkerpop-gremlin-server/bin/gremlin-server.sh stop
+PIDFile=/path/to/apache-tinkerpop-gremlin-server/run/gremlin.pid
+
+[Install]
+WantedBy=multi-user.target
+----
+
+
+Enable the service with `systemctl enable gremlin-server`
+
+Start the service with `systemctl start gremlin-server`
+
 
 [[security]]
-==== Security
+=== Security
 
 image:gremlin-server-secure.png[width=175,float=right] Gremlin Server provides for several features that aid in the
-security of the graphs that it exposes.  In particular it supports SSL for transport layer security, protective
-measures against malicious script execution, and authentication.  Client SSL options are described in the
+security of the graphs that it exposes.  In particular it supports SSL for transport layer security, authentication,
+authorization and protective measures against malicious script execution.  Client SSL options are described in the
 <<gremlin-drivers-variants, Gremlin Drivers and Variants">> sections with varying capability depending on the driver
 chosen. Script execution options are covered <<script-execution, "at the end of this section">>. This section
 starts with authentication.
@@ -1110,7 +1319,8 @@
 |Pluggable SASL |3.0.0-incubating
 |GSSAPI SASL (Kerberos) |3.3.0
 |Gremlin.NET |PLAIN SASL |3.3.0
-|Gremlin-Python |PLAIN SASL |3.2.2
+1.2+v|Gremlin-Python |PLAIN SASL |3.2.2
+|GSSAPI SASL (Kerberos) |3.4.7
 |Gremlin.Net |PLAIN SASL |3.2.7
 |Gremlin-Javascript |PLAIN SASL |3.3.0
 |=========================================================
@@ -1120,7 +1330,7 @@
 Server comes packaged with two implementations called `SimpleAuthenticator` for plain text authentication using HTTP
 BASIC or PLAIN SASL and `Krb5Authenticator` for Kerberos authentication using GSSAPI SASL.
 
-===== Plain text authentication
+==== Plain text authentication
 
 The `SimpleAuthenticator` implements the "PLAIN" SASL mechanism (i.e. plain text) to authenticate a request.  It also
 supports handling basic authentication requests from http clients. It validates
@@ -1231,7 +1441,7 @@
 curl -X POST --insecure -u stephen:password -d "{\"gremlin\":\"100-1\"}" "https://localhost:8182"
 
 [[credentials-dsl]]
-===== Credentials Graph DSL
+==== Credentials Graph DSL
 
 The "credentials graph", which has been mentioned in previous sections, is used by Gremlin Server to hold the list of
 users who can authenticate to the server.  It is possible to use virtually any `Graph` instance for this task as long
@@ -1276,7 +1486,7 @@
 complete. Alternatively, use a persistent graph to hold the credentials and configure Gremlin Server accordingly.
 
 [[krb5authenticator]]
-===== Kerberos Authentication
+==== Kerberos Authentication
 
 The `Krb5Authenticator` implements the "GSSAPI" SASL mechanism (i.e. Kerberos) to authenticate a request from a Gremlin
 client.  It can be applied in an existing Kerberos environment and validates whether a
@@ -1290,14 +1500,21 @@
     principal: gremlinserver/hostname.your.org@YOUR.REALM,
     keytab: /etc/security/keytabs/gremlinserver.service.keytab}}
 
-Krb5Authenticator needs a Kerberos service principal and a keytab that holds the secret key for that principal. The keytab
-location and service name, e.g. gremlinserver, are free to be chosen, but Gremlin clients have to specify this service name
-as the `protocol`. For Gremlin-Console the `protocol` is an entry in the remote.yaml file, for Gremlin-java the client builder
-has a `protocol()` method.
+`Krb5Authenticator` needs a Kerberos service principal and a keytab that holds the secret key for that principal. The keytab
+location and service name, e.g. gremlinserver, are free to be chosen. `Krb5Authenticator` finds the KDC's hostname and
+port from the krb5.conf file with Kerberos configurations. This file can reside at either the
+https://web.mit.edu/kerberos/krb5-devel/doc/mitK5defaults.html[default location] or a location to be specified as a
+system property in the JAVA_OPTIONS environment variable of Gremlin Server:
+
+[source, bash]
+export JAVA_OPTIONS="${JAVA_OPTIONS} -Xms512m -Xmx4096m -Djava.security.krb5.conf=/etc/krb5.conf"
+
+Gremlin clients have to specify the service name as the `protocol` connection parameter. For Gremlin-Console the
+`protocol` is an entry in the remote.yaml file, for Gremlin-java the client builder has a `protocol()` method.
 
 In addition to the `protocol`, the Gremlin client needs to specify a `jaasEntry`, an entry in the
-link:https://en.wikipedia.org/wiki/Java_Authentication_and_Authorization_Service[JAAS] configuration file. Gremlin-Console
-comes with a sample gremlin-jaas.conf file with a `GremlinConsole` jaasEntry:
+link:https://en.wikipedia.org/wiki/Java_Authentication_and_Authorization_Service[JAAS] configuration file. As a
+start one can define a conf/gremlin-jaas.conf file with a `GremlinConsole` jaasEntry:
 
 [source, jaas]
 GremlinConsole {
@@ -1306,18 +1523,355 @@
   useTicketCache=true;
 };
 
-This configuration tells Gremlin-Console to pass authentication requests from gremlin-server to the Krb5LoginModule, which is
-part of the java standard library.  The Krb5LoginModule does not prompt the user for a username and password but uses the ticket cache that
-is normally refreshed when a user logs in to a host within the Kerberos realm.
+This configuration tells Gremlin Console to pass authentication requests from Gremlin Server to the Krb5LoginModule, which is
+part of the java standard library. The Krb5LoginModule does not prompt the user for a username and password but uses the
+ticket cache that is normally refreshed when a user logs in to a host within the Kerberos realm.
 
-Finally, the Gremlin client needs the location of the JAAS configuration file to be passed as a system property to the JVM. For
-Gremlin-Console the easiest way to do this is to pass it to the run script via the JAVA_OPTIONS environment property:
+The Gremlin client needs the location of the JAAS configuration file to be passed as a system property to the JVM. For
+Gremlin-Console the easiest way to do this is to pass it to the run script via the JAVA_OPTIONS environment property.
+If the krb5.conf Kerberos configuration file is not available from the
+https://web.mit.edu/kerberos/krb5-devel/doc/mitK5defaults.html[default location] it has to be provided as a system
+property as well:
 
 [source, bash]
-export JAVA_OPTIONS="$JAVA_OPTIONS -Djava.security.auth.login.config=conf/gremlin-jaas.conf"
+JAAS_OPTION="-Djava.security.auth.login.config=conf/gremlin-jaas.conf"
+KRB5_OPTION="-Djava.security.krb5.conf=/etc/krb5.conf"
+export JAVA_OPTIONS="${JAVA_OPTIONS} ${KRB5_OPTION} ${JAAS_OPTION}"
+
+[[authorization]]
+==== Authorization
+
+While authentication determines which clients can connect to Gremlin Server, authorization regulates which elements
+of the exposed graphs a specific user is allowed to create, read, update or delete (CRUD). Authorization in Gremlin
+Server can take place at two instances. Before execution a user request can be allowed or denied based on the
+presence of operations such as:
+
+* reading from a GraphTraversalSource
+* writing to a GraphTraversalSource
+* presence of lambdas in bytecode
+* script execution
+* `VertexProgram` execution (OLAP)
+* removal or modification of `TraversalStrategy` instances
+
+During execution the applied traversal strategies influence the results and side-effects of a given query.
+
+IMPORTANT: Authorization is a feature of Gremlin Server, but is not implemented as an element of the server protocol
+and therefore Remote Graph Providers may not have this feature or may not implement it in this particular way. Please
+consult the documentation of the graph you are using to determine what authorization features it supports.
+
+===== Mechanisms
+
+Gremlin Server supports three mechanisms to configure authorization:
+
+. With the `ScriptFileGremlinPlugin` a groovy script is configured that instantiates the `GraphTraversalSources` that
+can be accessed by client requests. Using the `withStrategies()` gremlin
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#start-steps[start step], one can apply so-called
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#traversalstrategy[TraversalStrategy instances] to these
+`GraphTraversalSource` instances, some of which can serve for authorization purposes (`ReadOnlyStrategy`,
+`LambdaRestrictionStrategy`, `VertexProgramRestrictionStrategy`, `SubgraphStrategy`, `PartitionStrategy`,
+`EdgeLabelVerificationStrategy`), provided that users are not allowed to remove or modify these `TraversalStrategy`
+instances afterwards. The `ScriptFileGremlinPlugin` is found in the yaml configuration file for Gremlin Server:
++
+[source,yaml]
+----
+scriptEngines: {
+  gremlin-groovy: {
+    plugins: {
+      org.apache.tinkerpop.gremlin.jsr223.ScriptFileGremlinPlugin: {files: [scripts/empty-sample.groovy]}}}}
+----
+. Administrators can configure an authorizer class, an implementation of the `Authorizer` interface. An authorizer receives
+a request before it is executed and it can decide to pass or deny the request, based on the information it has available
+on the requesting user or can seek externally.
+. Apart from passing or denying requests, an `Authorizer` implementation can actively modify the request, in particular
+add the `TraversalStrategy` instances mentioned in item 1.
+
+IMPORTANT: This section is written with gremlin bytecode requests in mind. Realizing authorization for script requests
+is hardly feasible, because such requests get full access to Gremlin Server's execution environment. Although the section
+<<script-execution>> explains how the client access to this environment can be restricted, it is not possible to deny
+execution of `GraphFactory.open()` or `GraphTraversalSource.getGraph()` methods without resorting to TinkerPop
+implementation details (that is, internal API's that can change without notice).
+
+The three mechanisms for authorization each have their merits in terms of simplicity and flexibility. The table below
+gives an overview.
+
+[width="95%",cols="5,2,2,4",options="header"]
+|=========================================================
+|Type (mechanism) |GraphTraversalSources |Groups |Bytecode analysis
+|Implicit (init script) | all accessible |one |`withStrategies()`
+|Passive (pass/deny) | selected access |few |hybrid
+|Active (inject) |selected access |many |hybrid
+|=========================================================
+
+With implicit authorization (only adding restricting `TraversalStrategy` instances in the initialization script of
+Gremlin Server) all authenticated users can access all hosted `GraphTraversalSources` and all face the same
+restrictions. One would need separate Gremlin Server instances for each authorization policy and apply an authenticator
+that restricts access to a group of users (that is, supports in authorization).
+
+The other extreme is the active authorization solution that injects the restricting `Strategies` into the user request,
+following a policy that takes into account both the authenticated user and the original request. While this solution is
+the most flexible and can support an almost unlimited number of authorization policies, it is somewhat complex to
+implement. In particular, applying the `SubgraphStrategy` requires knowledge about the schema of the graph.
+
+The passive authorization solution perhaps provides a middle ground to start implementing authorization. This
+solution assumes that the `SubgraphStrategy` is applied in the Gremlin Server initialization script, because compliance
+with a subgraph restriction can only be determined during the actual execution of the gremlin traversal. Note that the
+same graph can be reused with different `SubgraphStrategies`. Now, authorization policies can be defined in terms of
+accessible `GraphTraversalSources` and the authorizer can simply match the requested access to a `GraphTraversalSource`
+against the policies applicable to the authenticated user. Like for the active authorization solution, other restrictions
+such as read only access can be either applied at authorization time as policy in the authorizer itself or at request
+execution time as a result of an applied `Strategy` (denoted as 'hybrid' bytecode analysis in the table). A code
+example pursuing the former option is provided in the <<authz-code-example, next section>>.
+
+NOTE: Both the passive and active authorization solutions need to analyze the gremlin bytecode of the original request
+for unwanted removal of restricting Strategies.
+
+NOTE: Gremlin Server is not shipped with `Authorizer` implementations, because these would heavily depend on the external
+systems to integrate with, e.g. link:https://ldap.com/directory-servers/[LDAP systems] or
+link:https://ranger.apache.org/[Apache Ranger ]. However, third-party implementations can be
+offered as <<gremlin-plugins, gremlin plugins>>.
+
+[[authz-code-example]]
+===== Code example
+
+The two java classes below provide an example implementation of the `Authorizer` interface; they originate from
+link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/authz[Gremlin Server's test package].
+If you copy the files into a project, build them into a jar and add the jar to Gremlin Server's CLASSPATH, you can use
+them by adding the following to Gremlin Server's yaml configuration file:
+
+[source, yaml]
+----
+authentication: {
+  authenticator: org.apache.tinkerpop.gremlin.server.auth.SimpleAuthenticator,
+  config: {
+    credentialsDb: conf/tinkergraph-credentials.properties}}
+authorization: {
+  authorizer: org.yourpackage.AllowListAuthorizer,
+  config: {
+    authorizationAllowList: your/path/allow-list.yaml}}
+----
+
+The `AllowListAuthorizer` supports granting groups of users access to statically configured `GraphTraversalSource`
+instances and to the "sandbox", where sandbox means that the group is allowed anything unless restricted by Gremlin
+Server's <<script-execution,sandbox>>. For denying mutating steps and OLAP operations in bytecode requests, the
+`AllowListAuthorizer` relies on the `ReadOnlyStrategy` and `VertexProgramRestrictionStrategy` being present in the
+`GraphTraversalSource`. However, it always denies the use of lambdas in bytecode requests unless the user has the
+"sandbox" grant. It uses the `BytecodeHelper.getLambdaLanguage()` method to detect these.
+
+The grants to groups of users can be configured in a simple yaml file. In addition to the special value "sandbox" for
+a grant for string based requests and lambdas, the special value "anonymous" can be used to denote any user.
+
+[source,java]
+----
+package org.yourpackage;
+
+import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
+import org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.verification.VertexProgramRestrictionStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.util.BytecodeHelper;
+import org.apache.tinkerpop.gremlin.server.Settings.AuthorizationSettings;
+import org.apache.tinkerpop.gremlin.server.auth.AuthenticatedUser;
+
+import java.util.*;
+
+/**
+ * Authorizes a user per request, based on a list that grants access to {@link TraversalSource} instances for
+ * bytecode requests and to gremlin server's sandbox for string requests and lambdas. The {@link
+ * AuthorizationSettings}.config must have an authorizationAllowList entry that contains the name of a YAML file.
+ * This authorizer is for demonstration purposes only. It does not scale well in the number of users regarding
+ * memory usage and administrative burden.
+ */
+public class AllowListAuthorizer implements Authorizer {
+
+    public static final String SANDBOX = "sandbox";
+    public static final String REJECT_BYTECODE = "User not authorized for bytecode requests on %s";
+    public static final String REJECT_LAMBDA = "lambdas";
+    public static final String REJECT_MUTATE = "the ReadOnlyStrategy";
+    public static final String REJECT_OLAP = "the VertexProgramRestrictionStrategy";
+    public static final String REJECT_SUBGRAPH = "the SubgraphStrategy";
+    public static final String REJECT_STRING = "User not authorized for string-based requests.";
+    public static final String KEY_AUTHORIZATION_ALLOWLIST = "authorizationAllowList";
+
+    // Collections derived from the list with allowed users for fast lookups
+    private final Map<String, List<String>> usernamesByTraversalSource = new HashMap<>();
+    private final Set<String> usernamesSandbox = new HashSet<>();
+
+    /**
+     * This method is called once upon system startup to initialize the {@code AllowListAuthorizer}.
+     */
+    @Override
+    public void setup(final Map<String,Object> config) {
+        AllowList allowList;
+        final String file = (String) config.get(KEY_AUTHORIZATION_ALLOWLIST);
+
+        try {
+            allowList = AllowList.read(file);
+        } catch (Exception e) {
+            throw new IllegalArgumentException(String.format("Failed to read list with allowed users from %s", file));
+        }
+        for (Map.Entry<String, List<String>> entry : allowList.grants.entrySet()) {
+            if (!entry.getKey().equals(SANDBOX)) {
+                usernamesByTraversalSource.put(entry.getKey(), new ArrayList<>());
+            }
+            for (final String group : entry.getValue()) {
+                if (allowList.groups.get(group) == null) {
+                    throw new RuntimeException(String.format("Group '%s' not defined in file with allowed users.", group));
+                }
+                if (entry.getKey().equals(SANDBOX)) {
+                    usernamesSandbox.addAll(allowList.groups.get(group));
+                } else {
+                    usernamesByTraversalSource.get(entry.getKey()).addAll(allowList.groups.get(group));
+                }
+            }
+        }
+    }
+
+    /**
+     * Checks whether a user is authorized to have a gremlin bytecode request from a client answered and raises an
+     * {@link AuthorizationException} if this is not the case. For a request to be authorized, the user must either
+     * have a grant for the requested {@link TraversalSource}, without using lambdas, mutating steps or OLAP, or have a
+     * sandbox grant.
+     *
+     * @param user {@link AuthenticatedUser} that needs authorization.
+     * @param bytecode The gremlin {@link Bytecode} request to authorize the user for.
+     * @param aliases A {@link Map} with a single key/value pair that maps the name of the {@link TraversalSource} in the
+     *                {@link Bytecode} request to name of one configured in Gremlin Server.
+     * @return The original or modified {@link Bytecode} to be used for further processing.
+     */
+    @Override
+    public Bytecode authorize(final AuthenticatedUser user, final Bytecode bytecode, final Map<String, String> aliases) throws AuthorizationException {
+        final Set<String> usernames = new HashSet<>();
+
+        for (final String resource: aliases.values()) {
+            usernames.addAll(usernamesByTraversalSource.get(resource));
+        }
+        final boolean userHasTraversalSourceGrant = usernames.contains(user.getName()) || usernames.contains(AuthenticatedUser.ANONYMOUS_USERNAME);
+        final boolean userHasSandboxGrant = usernamesSandbox.contains(user.getName()) || usernamesSandbox.contains(AuthenticatedUser.ANONYMOUS_USERNAME);
+        final boolean runsLambda = BytecodeHelper.getLambdaLanguage(bytecode).isPresent();
+        final boolean touchesReadOnlyStrategy = bytecode.toString().contains(ReadOnlyStrategy.class.getSimpleName());
+        final boolean touchesOLAPRestriction = bytecode.toString().contains(VertexProgramRestrictionStrategy.class.getSimpleName());
+        // This element becomes obsolete after resolving TINKERPOP-2473 for allowing only a single instance of each traversal strategy.
+        final boolean touchesSubgraphStrategy = bytecode.toString().contains(SubgraphStrategy.class.getSimpleName());
+
+        final List<String> rejections = new ArrayList<>();
+        if (runsLambda) {
+            rejections.add(REJECT_LAMBDA);
+        }
+        if (touchesReadOnlyStrategy) {
+            rejections.add(REJECT_MUTATE);
+        }
+        if (touchesOLAPRestriction) {
+            rejections.add(REJECT_OLAP);
+        }
+        if (touchesSubgraphStrategy) {
+            rejections.add(REJECT_SUBGRAPH);
+        }
+        String rejectMessage = REJECT_BYTECODE;
+        if (rejections.size() > 0) {
+            rejectMessage += " using " + String.join(", ", rejections);
+        }
+        rejectMessage += ".";
+
+        if ( (!userHasTraversalSourceGrant || runsLambda || touchesOLAPRestriction || touchesReadOnlyStrategy || touchesSubgraphStrategy) && !userHasSandboxGrant) {
+            throw new AuthorizationException(String.format(rejectMessage, aliases.values()));
+        }
+        return bytecode;
+    }
+
+    /**
+     * Checks whether a user is authorized to have a script request from a gremlin client answered and raises an
+     * {@link AuthorizationException} if this is not the case.
+     *
+     * @param user {@link AuthenticatedUser} that needs authorization.
+     * @param msg {@link RequestMessage} in which the {@link org.apache.tinkerpop.gremlin.driver.Tokens}.ARGS_GREMLIN argument can contain an arbitrary succession of script statements.
+     */
+    public void authorize(final AuthenticatedUser user, final RequestMessage msg) throws AuthorizationException {
+        if (!usernamesSandbox.contains(user.getName())) {
+            throw new AuthorizationException(REJECT_STRING);
+        }
+    }
+}
+----
+
+[source,java]
+----
+package org.yourpackage;
+
+import org.yaml.snakeyaml.TypeDescription;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * AllowList for the AllowListAuthorizer as configured by a YAML file.
+ */
+public class AllowList {
+
+    /**
+     * Holds lists of groups by grant. A grant is either a TraversalSource name or the "sandbox" value. With the
+     * sandbox grant users can access all TraversalSource instances and execute groovy scripts as string based
+     * requests or as lambda functions, only limited by Gremlin Server's sandbox definition.
+     */
+    public Map<String, List<String>> grants;
+
+    /**
+     * Holds lists of user names by groupname. The "anonymous" user name can be used to denote any user.
+     */
+    public Map<String, List<String>> groups;
+
+    /**
+     * Read a configuration from a YAML file into an {@link AllowList} object.
+     *
+     * @param file the location of a AllowList YAML configuration file
+     * @return An {@link Optional} object wrapping the created {@link AllowList}
+     */
+    public static AllowList read(final String file) throws Exception {
+        final InputStream stream = new FileInputStream(new File(file));
+
+        final Constructor constructor = new Constructor(AllowList.class);
+        final TypeDescription allowListDescription = new TypeDescription(AllowList.class);
+        allowListDescription.putMapPropertyType("grants", String.class, Object.class);
+        allowListDescription.putMapPropertyType("groups", String.class, Object.class);
+        constructor.addTypeDescription(allowListDescription);
+
+        final Yaml yaml = new Yaml(constructor);
+        return yaml.loadAs(stream, AllowList.class);
+    }
+}
+----
+
+
+allow-list.yaml:
+[source,yaml]
+----
+grants: {
+gclassic: [groupclassic],
+gmodern: [groupmodern],
+gcrew: [groupclassic, groupmodern],
+ggrateful: [groupgrateful],
+sandbox: [groupsandbox]
+}
+
+groups: {
+groupclassic: [userclassic],
+groupmodern: [usermodern, stephen],
+groupsink: [usersink],
+groupgrateful: [anonymous],
+groupsandbox: [usersandbox, marko]
+}
+----
+
 
 [[script-execution]]
-===== Protecting Script Execution
+==== Protecting Script Execution
 
 It is important to remember that Gremlin Server exposes `GremlinScriptEngine` instances that allows for remote execution
 of arbitrary code on the server.  Obviously, this situation can represent a security risk or, more minimally, provide
@@ -1485,206 +2039,6 @@
 can fine tune the Groovy compilation process.  Read more about compilation customization in the
 link:http://docs.groovy-lang.org/latest/html/documentation/#compilation-customizers[Groovy Documentation].
 
-==== Serialization
-
-Gremlin Server can accept requests and return results using different serialization formats. Serializers implement the
-`MessageSerializer` interface. In doing so, they express the list of mime types they expect to support. When
-configuring multiple serializers it is possible for two or more serializers to support the same mime type. Such a
-situation may be common with a generic mime type such as `application/json`. Serializers are added in the order that
-they are encountered in the configuration file and the first one added for a specific mime type will not be overridden
-by other serializers that also support it.
-
-The format of the serialization is configured by the `serializers` setting described in the table above.  Note that
-some serializers have additional configuration options as defined by the `serializers[X].config` setting.  The
-`config` setting is a `Map` where the keys and values get passed to the serializer at its initialization.  The
-available and/or expected keys are dependent on the serializer being used.  Gremlin Server comes packaged with three
-different serializers: GraphSON, Gryo, and GraphBinary.
-
-===== GraphSON
-
-The GraphSON serializer produces human readable output in JSON format and is a good configuration choice for those
-trying to use TinkerPop from non-JVM languages.  JSON obviously has wide support across virtually all major
-programming languages and can be consumed by a wide variety of tools. The format itself is described in the
-link:https://tinkerpop.apache.org/docs/current/dev/io/#graphson[IO Documentation].
-
-[source,yaml]
-----
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV1d0 }
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV2d0 }
-----
-
-The above configuration represents the default serialization under the `application/json` MIME type and produces JSON
-consistent with standard JSON data types.  It has the following configuration option:
-
-[width="100%",cols="3,10,^2",options="header"]
-|=========================================================
-|Key |Description |Default
-|ioRegistries |A list of `IoRegistry` implementations to be applied to the serializer. |_none_
-|=========================================================
-
-[source,yaml]
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV1d0 }
-
-When the standard JSON data types are not enough (e.g. need to identify the difference between `double` and `float`
-data types), the above configuration will embed types into the JSON itself.  The type embedding uses standard Java
-type names, so interpretation from non-JVM languages will be required.  It has the MIME type of
-`application/vnd.gremlin-v1.0+json` and the following configuration options:
-
-[width="100%",cols="3,10,^2",options="header"]
-|=========================================================
-|Key |Description |Default
-|ioRegistries |A list of `IoRegistry` implementations to be applied to the serializer. |_none_
-|=========================================================
-
-===== Gryo
-
-The Gryo serializer utilizes Kryo-based serialization which produces a binary output.  This format is best consumed
-by JVM-based languages. The format itself is described in the
-link:https://tinkerpop.apache.org/docs/current/dev/io/#gryo[IO Documentation].
-
-[source,yaml]
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerGremlinV1d0 }
-
-It has the MIME type of `application/vnd.gremlin-v1.0+gryo` and the following configuration options:
-
-[width="100%",cols="3,10,^2",options="header"]
-|=========================================================
-|Key |Description |Default
-|bufferSize |The maximum size of the Kryo buffer for use on a single object being serialized.  Increasing this value will correct `KryoException` errors that complain of "Buffer too small". |_4096_
-|classResolverSupplier |The fully qualified classname of a custom `Supplier<ClassResolver>` which will be used when constructing `Kryo` instances. There is no direct default for this setting, but without a setting the `GryoClassResolver` is used. |_none_
-|custom |A list of classes with custom kryo `Serializer` implementations related to them in the form of `<class>;<serializer-class>`. |_none_
-|ioRegistries |A list of `IoRegistry` implementations to be applied to the serializer. |_none_
-|serializeResultToString |When set to `true`, results are serialized by first calling `toString()` on each object in the result list resulting in an extended MIME Type of `application/vnd.gremlin-v1.0+gryo-stringd`.  When set to `false` Kryo-based serialization is applied. |_false_
-|=========================================================
-
-As described above, there are multiple ways in which to register serializers for Kryo-based serialization.  Note
-that the `ioRegistries` setting is applied first, followed by the `custom` setting.
-
-Those configuring or implementing a `Supplier<ClassResolver>` should consider this an "advanced" option and typically
-important to use cases where server types need to be coerced to client types (i.e. a type is available on the server
-but not on the client).  Implementations should typically instantiate `ClassResolver` implementations that are
-extensions of the `GryoClassResolver` as this class is important to most serialization tasks in TinkerPop.
-
-===== GraphBinary
-
-GraphBinary is a binary serialization format suitable for object trees, designed to reduce serialization overhead on
-both the client and the server, as well as limiting the size of the payload that is transmitted over the wire. The
-format itself is described in the link:https://tinkerpop.apache.org/docs/current/dev/io/#graphbinary[IO Documentation].
-
-IMPORTANT: GraphBinary is currently only supported on the JVM.
-
-[source,yaml]
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1 }
-
-It has the MIME type of `application/vnd.graphbinary-v1.0` and the following configuration options:
-
-[width="100%",cols="3,10,^2",options="header"]
-|=========================================================
-|Key |Description |Default
-|custom |A list of classes with custom kryo `Serializer` implementations related to them in the form of `<class>;<serializer-class>`. |_none_
-|ioRegistries |A list of `IoRegistry` implementations to be applied to the serializer. |_none_
-|builder |Name of the `TypeSerializerRegistry.Builder` instance to be used to construct the `TypeSerializerRegistry`. |_none_
-|=========================================================
-
-As described above, there are multiple ways in which to register serializers for GraphBinary-based serialization. Note
-that the `ioRegistries` setting is applied first, followed by the `custom` setting.
-
-[[metrics]]
-==== Metrics
-
-Gremlin Server produces metrics about its operations that can yield some insight into how it is performing. These
-metrics are exposed in a variety of ways:
-
-* Directly to the console where Gremlin Server is running
-* CSV file
-* link:http://ganglia.info/[Ganglia]
-* link:http://graphite.wikidot.com/[Graphite]
-* link:http://www.slf4j.org/[SLF4j]
-* link:https://en.wikipedia.org/wiki/Java_Management_Extensions[JMX]
-
-The configuration of each of these outputs is described in the Gremlin Server <<_configuring_2, Configuring>> section.
-Note that Graphite and Ganglia are not included as part of the Gremlin Server distribution and must be installed
-to the server manually.
-
-[source,text]
-----
-bin/gremlin-server.sh install com.codahale.metrics metrics-ganglia 3.0.2
-bin/gremlin-server.sh install com.codahale.metrics metrics-graphite 3.0.2
-----
-
-WARNING: Gremlin Server is built to work with Metrics 3.0.2. Usage of other versions may lead to unexpected problems.
-
-NOTE: Installing Ganglia will include `org.acplt:oncrpc`, which is an LGPL licensed dependency.
-
-Regardless of the output, the metrics gathered are the same. Each metric is prefixed with
-`org.apache.tinkerpop.gremlin.server.GremlinServer` and the following metrics are reported:
-
-* `sessions` - the number of sessions open at the time the metric was last measured.
-* `errors` - the number of total errors, mean rate, as well as the 1, 5, and 15-minute error rates.
-* `op.eval` - the number of script evaluations, mean rate, 1, 5, and 15 minute rates, minimum, maximum, median, mean,
-and standard deviation evaluation times, as well as the 75th, 95th, 98th, 99th and 99.9th percentile evaluation times
-(note that these time apply to both sessionless and in-session requests).
-* `op.traversal` - the number of `Traversal` executions, mean rate, 1, 5, and 15 minute rates, minimum, maximum, median,
-mean, and standard deviation evaluation times, as well as the 75th, 95th, 98th, 99th and 99.9th percentile evaluation
-times.
-* `engine-name.session.session-id.*` - metrics related to different `GremlinScriptEngine` instances configured for
-session-based requests where "engine-name" will be the actual name of the engine, such as "gremlin-groovy" and
-"session-id" will be the identifier for the session itself.
-* `engine-name.sessionless.*` - metrics related to different `GremlinScriptEngine` instances configured for sessionless
-requests where "engine-name" will be the actual name of the engine, such as "gremlin-groovy".
-
-==== As A Service
-
-Gremlin server can be configured to run as a service.
-
-===== Init.d (SysV)
-
-Link `bin/gremlin-server.sh` to `init.d`
-Be sure to set RUNAS to the service user in `bin/gremlin-server.conf`
-
-[source,bash]
-----
-# Install
-ln -s /path/to/apache-tinkerpop-gremlin-server-x.y.z/bin/gremlin-server.sh /etc/init.d/gremlin-server
-
-# Systems with chkconfig/service. E.g. Fedora, Red Hat
-chkconfig --add gremlin-server
-
-# Start
-service gremlin-server start
-
-# Or call directly
-/etc/init.d/gremlin-server restart
-
-----
-
-===== Systemd
-
-To install, copy the service template below to /etc/systemd/system/gremlin.service
-and update the paths `/path/to/apache-tinkerpop-gremlin-server` with the actual install path of Gremlin Server.
-
-[source,bash]
-----
-[Unit]
-Description=Apache TinkerPop Gremlin Server daemon
-Documentation=https://tinkerpop.apache.org/
-After=network.target
-
-[Service]
-Type=forking
-ExecStart=/path/to/apache-tinkerpop-gremlin-server/bin/gremlin-server.sh start
-ExecStop=/path/to/apache-tinkerpop-gremlin-server/bin/gremlin-server.sh stop
-PIDFile=/path/to/apache-tinkerpop-gremlin-server/run/gremlin.pid
-
-[Install]
-WantedBy=multi-user.target
-----
-
-
-Enable the service with `systemctl enable gremlin-server`
-
-Start the service with `systemctl start gremlin-server`
-
 
 === Best Practices
 
@@ -1707,22 +2061,35 @@
 Section below.
 * When configuring the size of `threadPoolWorker` start with the default of `1` and increment by one as needed to a
 maximum of `2*number of cores`.
-* The "right" size of the `gremlinPool` setting is somewhat dependent on the type of scripts that will be processed
+* The "right" size of the `gremlinPool` setting is somewhat dependent on the type of requests that will be processed
 by Gremlin Server.  As requests arrive to Gremlin Server they are decoded and queued to be processed by threads in
 this pool.  When this pool is exhausted of threads, Gremlin Server will continue to accept incoming requests, but
 the queue will continue to grow.  If left to grow too large, the server will begin to slow.  When tuning around
 this setting, consider whether the bulk of the scripts being processed will be "fast" or "slow", where "fast"
 generally means being measured in the low hundreds of milliseconds and "slow" means anything longer than that.
-* Scripts that are "slow" can really hurt Gremlin Server if they are not properly accounted for.  `ScriptEngine`
-evaluations are blocking operations that aren't always easily interrupted, so once a "slow" script is being evaluated in
-the context of a `ScriptEngine` it must finish its work.  Lots of "slow" scripts will eventually consume the
-`gremlinPool` preventing other scripts from getting processed from the queue.
+* Requests that are "slow" can really hurt Gremlin Server if they are not properly accounted for. Since these requests
+block a thread until the job is complete or successfully interrupted, lots of long-run requests will eventually consume
+the `gremlinPool` preventing other requests from getting processed from the queue.
 ** To limit the impact of this problem, consider properly setting the `evaluationTimeout` to something "sane".
 In other words, test the traversals being sent to Gremlin Server and determine the maximum time they take to evaluate
-and iterate over results, then set the timeout value accordingly.
+and iterate over results, then set the timeout value accordingly. Also, consider setting a shorter global timeout for
+requests and then use longer per-request timeouts for those specific ones that might execute at a longer rate.
 ** Note that `evaluationTimeout` can only attempt to interrupt the evaluation on timeout.  It allows Gremlin
 Server to "ignore" the result of that evaluation, which means the thread in the `gremlinPool` that did the evaluation
 may still be consumed after the timeout if interruption does not succeed on the thread.
+* When using sessions, there are different options to consider depending on the `Channelizer` implementation being
+used:
+** `WebSocketChannelizer` and `WsAndHttpChannelizer` - Both of these channelizers use the `gremlinPool` only for
+sessionless requests and construct a single threaded pool for each session created. In this way, these channelizers
+tend to optimize sessions to be long-lived. For short-lived sessions, which may be typical when using bytecode based
+remote transactions, quickly creating and destroying these sessions can be expensive. It is likely that there will be
+increased garbage collection times and frequency as well as a general increase in overall server processing.
+** `UnifiedChannelizer` - The threads of the `gremlinPool` are used to service both sessions and sessionless requests.
+With a common thread pool, this channelizer is a better choice when using lots of short-lived sessions as compared to
+`WebSocketChannelizer` and `WsAndHttpChannelizer`, because there is less cost in starting and stopping sessions. It is
+important though to understand the expected workload for the server and plan the size accordingly to ensure that the
+server does not need to wait for an extended period of time for a thread to be available to process the queue of
+incoming requests.
 * Graph element serialization for `Vertex` and `Edge` can be expensive, as their data structures are complex given the
 possible existence of multi-properties and meta-properties. When returning data from Gremlin Server only return the
 data that is required. For example, if only two properties of a `Vertex` are needed then simply return the two rather
@@ -1882,10 +2249,6 @@
 case but GraphBinary will not. Therefore, script-based requests that use Gryo or GraphSON should definitely follow the
 best practice of only returning the data required by the application.
 
-NOTE: Gryo does have the exception for the `GryoMessageSerializerGremlinV1d0` with the `serializeResultToString`
-option enabled, which will simply convert all results using the Java `toString()` method prior to serialization and
-is typically only use by the Gremlin Console for remote sessions where the actual object from the server is not of use.
-
 For bytecode-based requests, graph elements have reference detachment and thus only return the `id` and `label` of
 the elements. While this approach alleviates a potential performance problem that the script approach exposes, it is
 still important to follow the practice of being specific about the data that is required by the requesting application
@@ -2060,6 +2423,28 @@
 if there was a failure in transaction management on the call to `commit()`, "a" would still be available to the next
 request.
 
+To avoid unexpected problems with state in relation to errors in sessions, it is best to follow these guidelines:
+
+* Do not re-use session identifiers. Simply use a new UUID for each session.
+* On exception, be sure to call `close()` on the `Client` and create a new session.
+* While you may submit parallel asynchronous requests to a session, it may not make sense to do so because they are
+simply executed serially as they arrive to the session. A failed asynchronous request could leave an invalid state
+in the session which may not allow later requests to succeed. Either use synchronous requests only or carefully
+consider error conditions with asynchronous requests.
+
+If using the `UnifiedChannelizer`, failures in evaluation will result in the session being closed and state being
+lost. Asynchronous requests that are queued on the server will be cancelled and additional requests, in-flight or
+otherwise will be rejected. Users should create a new session from the `Cluster` object in this case. The alternative,
+to match the old `OpProcessor` GremlinServer behavior, is to add the `maintainStateAfterException` session setting to
+`true` which will instead have similar behavior to that described in this section.
+
+[source,java]
+----
+Client.SessionSettings settings =
+    Client.SessionSettings.build().maintainStateAfterException(true).create();
+Client session = cluster.connect(Client.Settings.build().useSession(settings).create());
+----
+
 A session is a "heavier" approach to the simple "request/response" approach of sessionless requests, but is sometimes
 necessary for a given use case.
 
@@ -2137,6 +2522,14 @@
 In the above HTTP-based requests, the bindings contain a special parameter that tells the `ScriptEngine` cache to
 immediately forget the script after execution. In this way, the function does not end up being globally available.
 
+[[request-retry]]
+==== Request Retry
+
+The server has the ability to instruct the client that an error condition is transient and that the client should
+simply retry the request later. In the event a client detects a `ResponseStatusCode` of `SERVER_ERROR_TEMPORARY`,
+which is error code `596`, the client may choose to retry that request. Note that drivers do not have the ability to
+automatically retry and that it is up to the application to provide such logic.
+
 [[gremlin-server-docker-image]]
 === Docker Image
 
@@ -2388,7 +2781,7 @@
 link:http://en.wikipedia.org/wiki/Syntactic_sugar[syntactic sugars] that users could rely on to make their traversals
 more succinct. Unfortunately, many of these conventions made use of link:http://docs.oracle.com/javase/tutorial/reflect/[Java reflection]
 and thus, were not performant. In TinkerPop, these conveniences have been removed in support of the standard
-Gremlin-Groovy syntax being both inline with Gremlin-Java8 syntax as well as always being the most performant
+Gremlin-Groovy syntax being both inline with Gremlin-Java syntax as well as always being the most performant
 representation. However, for those users that would like to use the previous syntactic sugars (as well as new ones),
 there is `SugarGremlinPlugin` (a.k.a Gremlin-Groovy-Sugar).
 
diff --git a/docs/src/reference/gremlin-variants.asciidoc b/docs/src/reference/gremlin-variants.asciidoc
index cfb000b..7b79da4 100644
--- a/docs/src/reference/gremlin-variants.asciidoc
+++ b/docs/src/reference/gremlin-variants.asciidoc
@@ -27,22 +27,21 @@
 architecture and design of the application and the choice itself may have limits imposed upon it by the chosen graph
 provider. For example, a <<connecting-rgp,Remote Gremlin Provider>> will require the selection of a driver to interact
 with it. On the other hand, a graph system that is designed for embedded use, like TinkerGraph, needs the Java
-Virtual Machine (JVM) environment so will require <<connecting-gremlin-server,Gremlin Server>>, if using a programming
-language that is not on the JVM and will further require driver selection.
+Virtual Machine (JVM) environment which is easily accessed with a JVM programming language. If however the programming
+language is not built for the JVM then it will require <<connecting-gremlin-server,Gremlin Server>> in the architecture
+as well.
 
 TinkerPop provides an array of drivers in different programming languages as a way to connect to a remote Gremlin
 Server or Remote Gremlin Provider. Drivers allow the developer to make requests to that remote system and get back
 results from the TinkerPop-enabled graphs hosted within. A driver can submit Gremlin strings and Gremlin bytecode
 over this sub-protocol. Gremlin strings are written in the scripting language made available by the remote system that
 the driver is connecting to (typically, Groovy-based). This connection approach is quite similar to what developers
-are likely familiar with when using JDBC and SQL. While it is familiar, it is not recommended and for TinkerPop it is
-considered an out-dated concept and is largely still present for the purpose of supporting applications that might
-still be using that method of interaction.
+are likely familiar with when using JDBC and SQL.
 
 The preferred approach is to use bytecode-based requests, which essentially allows the ability to craft Gremlin
 directly in the programming language of choice. As Gremlin makes use of two fundamental programming constructs:
 link:https://en.wikipedia.org/wiki/Function_composition[function composition] and
-link:https://en.wikipedia.org/wiki/Nested_function[function nesting]. it is possible to embed the Gremlin language
+link:https://en.wikipedia.org/wiki/Nested_function[function nesting], it is possible to embed the Gremlin language
 in any modern programming language. It is a far more natural way to program, because it enables IDE interaction,
 compile time checks, and language level checks that can help prevent errors prior to execution. The differences
 between these two approaches were outlined in the <<connecting-via-drivers,Connecting Via Drivers>> Section, which
@@ -65,10 +64,6 @@
 
 image::gremlin-variant-architecture.png[width=650,float=left]
 
-NOTE: The information herein describes how to use the Gremlin language variants distributed
-with Apache TinkerPop. For information on how to build a Gremlin language variant, please review the
-link:https://tinkerpop.apache.org/docs/x.y.z/tutorials/gremlin-language-variants/[Gremlin Language Variants] tutorial.
-
 The following sections describe each language variant and driver that is officially TinkerPop a part of the project,
 provided more detailed information about usage, configuration and known limitations.
 
@@ -97,6 +92,24 @@
    <artifactId>gremlin-driver</artifactId>
    <version>x.y.z</version>
 </dependency>
+
+<!--
+alternatively the driver is packaged as an uberjar with shaded non-optional dependencies including gremlin-core and
+tinkergraph-gremlin which are not shaded.
+-->
+<dependency>
+   <groupId>org.apache.tinkerpop</groupId>
+   <artifactId>gremlin-driver</artifactId>
+   <version>x.y.z</version>
+   <classifier>shaded</classifier>
+   <!-- The shaded JAR uses the original POM, therefore conflicts may still need resolution -->
+   <exclusions>
+      <exclusion>
+         <groupId>io.netty</groupId>
+         <artifactId>*</artifactId>
+      </exclusion>
+   </exclusions>
+</dependency>
 ----
 
 [[gremlin-java-connecting]]
@@ -180,10 +193,10 @@
 ----
 
 Note the call to `close()` above. The call to `withRemote()` internally instantiates a connection via the driver that
-can only be released by "closing" the `GraphTraversalSource`. It is important to take that step to release resources
-created in that step.
+can only be released by "closing" the `GraphTraversalSource`. It is important to take that step to release network
+resources associated with `g`.
 
-If working with multiple remote `TraversalSource` instances it is more efficient to construct `Cluster` and `Client
+If working with multiple remote `TraversalSource` instances it is more efficient to construct `Cluster` and `Client`
 objects and then re-use them.
 
 [gremlin-groovy]
@@ -202,10 +215,6 @@
 `Cluster` objects must also be closed explicitly. It's worth noting that the close of a `Cluster` will close all
 `Client` instances spawned by the `Cluster`.
 
-IMPORTANT: Bytecode-based traversals use the `TraversalOpProcessor` in Gremlin Server which requires a cache to enable
-the retrieval of side-effects (if the `Traversal` produces any). That cache can be configured (e.g. controlling
-eviction times and sizing) in the Gremlin Server configuration file as described <<traversalopprocessor, here>>.
-
 Some connection options can also be set on individual requests made through the Java driver using `with()` step
 on the `TraversalSource`. For instance to set request timeout to 500 milliseconds:
 
@@ -296,18 +305,17 @@
 
 Remote systems like Gremlin Server and Remote Gremlin Providers respond to requests made in a particular serialization
 format and respond by serializing results to some format to be interpreted by the client. For JVM-based languages,
-there are three options for serialization: Gryo, GraphSON and GraphBinary. When using Gryo serialization (the default
-serializer for the Java driver), it is important that the client and server have the same serializers configured or
-else one or the other will experience serialization exceptions and fail to always communicate. Discrepancy in
-serializer registration between client and server can happen fairly easily as graphs will automatically include
-serializers on the server-side, thus leaving the client to be configured manually. This can be done manually as
-follows:
+there are three options for serialization: Gryo, GraphSON and GraphBinary. It is important that the client and server
+have the same serializers configured in the same way or else one or the other will experience serialization exceptions
+and fail to always communicate. Discrepancy in serializer registration between client and server can happen fairly
+easily as different graph systems may automatically include serializers on the server-side, thus leaving the client
+to be configured manually. As an example:
 
 [source,java]
 ----
 IoRegistry registry = ...; // an IoRegistry instance exposed by a specific graph provider
-GryoMapper kryo = GryoMapper.build().addRegistry(registry).create();
-MessageSerializer serializer = new GryoMessageSerializerV3d0(kryo);
+TypeSerializerRegistry typeSerializerRegistry = TypeSerializerRegistry.build().addRegistry(registry).create();
+MessageSerializer serializer = new GraphBinaryMessageSerializerV1(typeSerializerRegistry);
 Cluster cluster = Cluster.build().
                           serializer(serializer).
                           create();
@@ -317,10 +325,12 @@
 
 The `IoRegistry` tells the serializer what classes from the graph provider to auto-register during serialization.
 Gremlin Server roughly uses this same approach when it configures its serializers, so using this same model will
-ensure compatibility when making requests. Obviously, it is possible to switch to GraphSON or GraphBinary by building
-the appropriate `MessageSerializer` (`GraphSONMessageSerializerV3d0` or `GraphBinaryMessageSerializerV1` respectively)
+ensure compatibility when making requests. Obviously, it is possible to switch to GraphSON or Gryo by using
+the appropriate `MessageSerializer` (e.g. `GraphSONMessageSerializerV3d0` or `GryoMessageSerializerV3d0` respectively)
 in the same way and building that into the `Cluster` object.
 
+NOTE: Gryo is no longer the preferred binary serialization format for Gremlin Server - please prefer GraphBinary.
+
 [[gremlin-java-lambda]]
 === The Lambda Solution
 
@@ -377,10 +387,6 @@
 [[gremlin-java-scripts]]
 === Submitting Scripts
 
-WARNING: TinkerPop does not recommend submitting script-based requests and generally continues to support this feature
-for legacy reasons and corner use cases which are still not completely addressed by the Gremlin language. Please
-consider using bytecode-based requests instead when possible.
-
 image:gremlin-java.png[width=175,float=left] TinkerPop comes equipped with a reference client for Java-based
 applications.  It is referred to as `gremlin-driver`, which enables applications to send requests to Gremlin Server
 and get back results.
@@ -670,6 +676,7 @@
 [source,bash]
 ----
 pip install gremlinpython
+pip install gremlinpython[kerberos]     # Optional, not available on Microsoft Windows
 ----
 
 [[gremlin-python-connecting]]
@@ -689,9 +696,36 @@
 
 [source,python]
 ----
-g = traversal().withRemote(DriverRemoteConnection('ws://localhost:8182/gremlin','g',headers={'Header':'Value'}))
+g = traversal().withRemote(DriverRemoteConnection(
+    'ws://localhost:8182/gremlin', 'g', headers={'Header':'Value'}))
 ----
 
+Gremlin-Python supports plain text and Kerberos SASL authentication, you can set it on the connection options.
+
+[source,python]
+----
+# Plain text authentication
+g = traversal().withRemote(DriverRemoteConnection(
+    'ws://localhost:8182/gremlin', 'g', username='stephen', password='password'))
+
+# Kerberos authentication
+g = traversal().withRemote(DriverRemoteConnection(
+    'ws://localhost:8182/gremlin', 'g', kerberized_service='gremlin@hostname.your.org'))
+----
+
+The value specified for the kerberized_service should correspond to the first part of the principal name configured for
+the gremlin service, but with the slash replaced by an _at_ sign. The Gremlin-Python client reads the kerberos
+configurations from your system. It finds the KDC's hostname and port from the krb5.conf file at the
+https://web.mit.edu/kerberos/krb5-devel/doc/mitK5defaults.html[default location] or as indicated in the KRB5_CONFIG
+environment variable. It finds credentials from the credential cache or a keytab file at the
+https://web.mit.edu/kerberos/krb5-devel/doc/mitK5defaults.html[default locations] or as indicated
+in the KRB5CCNAME or KRB5_KTNAME environment variables.
+
+If you authenticate to a remote <<connecting-gremlin-server,Gremlin Server>> or
+<<connecting-rgp,Remote Gremlin Provider>>, this server normally has SSL activated and the websockets url will start
+with 'wss://'. If Gremlin-Server uses a self-signed certificate for SSL, Gremlin-Python needs access to a local copy of
+the CA certificate file (in openssl .pem format), to be specified in the SSL_CERT_FILE environment variable.
+
 NOTE: If connecting from an inherently single-threaded Python process where blocking while waiting for Gremlin
 traversals to complete is acceptable, it might be helpful to set `pool_size` and `max_workers` parameters to 1.
 See the <<python-configuration,Configuration>> section just below.  Examples where this could apply are serverless cloud functions or WSGI
@@ -738,9 +772,10 @@
 
 These can be used analogously to how they are used in Gremlin-Java.
 
-[gremlin-python,modern]
+[source,python]
 ----
-g.V().hasLabel('person').has('age',P.gt(30)).order().by('age',Order.desc).toList()
+>>> g.V().hasLabel('person').has('age',P.gt(30)).order().by('age',Order.desc).toList()
+[v[6], v[4]]
 ----
 
 Moreover, by importing the `statics` of Gremlin-Python, the class prefixes can be omitted.
@@ -752,17 +787,19 @@
 
 With statics loaded its possible to represent the above traversal as below.
 
-[gremlin-python,modern]
+[source,python]
 ----
-g.V().hasLabel('person').has('age',gt(30)).order().by('age',desc).toList()
+>>> g.V().hasLabel('person').has('age',gt(30)).order().by('age',desc).toList()
+[v[6], v[4]]
 ----
 
 Statics includes all the `+__+`-methods and thus, anonymous traversals like `+__.out()+` can be expressed as below.
 That is, without the `+__+`-prefix.
 
-[gremlin-python,modern]
+[source,python]
 ----
-g.V().repeat(out()).times(2).name.fold().toList()
+>>> g.V().repeat(out()).times(2).name.fold().toList()
+[['ripple', 'lop']]
 ----
 
 There may be situations where certain graphs may want a more exact data type than what Python will allow as a language.
@@ -794,13 +831,16 @@
 |password |The password to submit on requests that require authentication. |""
 |pool_size |The number of connections used by the pool. |4
 |protocol_factory |A callable that returns an instance of `AbstractBaseProtocol`. |`gremlin_python.driver.protocol.GremlinServerWSProtocol`
-|transport_factory |A callable that returns an instance of `AbstractBaseTransport`. |`gremlin_python.driver.tornado.transport.TornadoTransport`
+|transport_factory |A callable that returns an instance of `AbstractBaseTransport`. |`gremlin_python.driver.aiohttp.transport.AiohttpTransport`
 |username |The username to submit on requests that require authentication. |""
+|kerberized_service |the first part of the principal name configured for the gremlin service|"""
 |session | A unique string-based identifier (typically a UUID) to enable a <<sessions,session-based connection>>. This is not a valid configuration for `DriverRemoteConnection`. |None
 |=========================================================
 
-Note that the `transport_factory` can allow for additional configuration of the `TornadoTransport`, which exposes
-options to manage `ioloop` timeouts and compression settings:
+Note that the `transport_factory` can allow for additional configuration of the `AiohttpTransport`, which allows
+pass through of the named parameters available in
+link:https://docs.aiohttp.org/en/stable/client_reference.html#aiohttp.ClientSession.ws_connect[AIOHTTP's ws_connect],
+and the ability to call the api from an event loop:
 
 [source,python]
 ----
@@ -808,9 +848,11 @@
 ...
 g = traversal().withRemote(
   DriverRemoteConnection('ws://localhost:8182/gremlin','g',
-                         transport_factory=lambda: TornadoTransport(read_timeout=10,
+                         transport_factory=lambda: AiohttpTransport(read_timeout=10,
                                                                     write_timeout=10,
-                                                                    compression_options={'compression_level':5,'mem_level':5},
+                                                                    heartbeat=1.0,
+                                                                    call_from_event_loop=True
+                                                                    max_content_length=100*1024*1024,
                                                                     ssl_options=ssl.create_default_context(Purpose.CLIENT_AUTH))))
 ----
 
@@ -824,17 +866,23 @@
 In order to add and remove <<traversalstrategy,traversal strategies>> from a traversal source, Gremlin-Python has a
 `TraversalStrategy` class along with a collection of subclasses that mirror the standard Gremlin-Java strategies.
 
-[gremlin-python,modern]
+[source,python]
 ----
-g = g.withStrategies(SubgraphStrategy(vertices=hasLabel('person'),edges=has('weight',gt(0.5))))
-g.V().name.toList()
-g.V().outE().elementMap().toList()
-g = g.withoutStrategies(SubgraphStrategy)
-g.V().name.toList()
-g.V().outE().elementMap().toList()
-g = g.withComputer(workers=2,vertices=has('name','marko'))
-g.V().name.toList()
-g.V().outE().valueMap().with_(WithOptions.tokens).toList()
+>>> g = g.withStrategies(SubgraphStrategy(vertices=hasLabel('person'),edges=has('weight',gt(0.5))))
+>>> g.V().name.toList()
+['marko', 'vadas', 'josh', 'peter']
+>>> g.V().outE().elementMap().toList()
+[{<T.id: 1>: 8, <T.label: 4>: 'knows', <Direction.IN: 2>: {<T.id: 1>: 4, <T.label: 4>: 'person'}, <Direction.OUT: 3>: {<T.id: 1>: 1, <T.label: 4>: 'person'}, 'weight': 1.0}]
+>>> g = g.withoutStrategies(SubgraphStrategy)
+>>> g.V().name.toList()
+['marko', 'vadas', 'lop', 'josh', 'ripple', 'peter']
+>>> g.V().outE().elementMap().toList()
+[{<T.id: 1>: 9, <T.label: 4>: 'created', <Direction.IN: 2>: {<T.id: 1>: 3, <T.label: 4>: 'software'}, <Direction.OUT: 3>: {<T.id: 1>: 1, <T.label: 4>: 'person'}, 'weight': 0.4}, {<T.id: 1>: 7, <T.label: 4>: 'knows', <Direction.IN: 2>: {<T.id: 1>: 2, <T.label: 4>: 'person'}, <Direction.OUT: 3>: {<T.id: 1>: 1, <T.label: 4>: 'person'}, 'weight': 0.5}, {<T.id: 1>: 8, <T.label: 4>: 'knows', <Direction.IN: 2>: {<T.id: 1>: 4, <T.label: 4>: 'person'}, <Direction.OUT: 3>: {<T.id: 1>: 1, <T.label: 4>: 'person'}, 'weight': 1.0}, {<T.id: 1>: 10, <T.label: 4>: 'created', <Direction.IN: 2>: {<T.id: 1>: 5, <T.label: 4>: 'software'}, <Direction.OUT: 3>: {<T.id: 1>: 4, <T.label: 4>: 'person'}, 'weight': 1.0}, {<T.id: 1>: 11, <T.label: 4>: 'created', <Direction.IN: 2>: {<T.id: 1>: 3, <T.label: 4>: 'software'}, <Direction.OUT: 3>: {<T.id: 1>: 4, <T.label: 4>: 'person'}, 'weight': 0.4}, {<T.id: 1>: 12, <T.label: 4>: 'created', <Direction.IN: 2>: {<T.id: 1>: 3, <T.label: 4>: 'software'}, <Direction.OUT: 3>: {<T.id: 1>: 6, <T.label: 4>: 'person'}, 'weight': 0.2}]
+>>> g = g.withComputer(workers=2,vertices=has('name','marko'))
+>>> g.V().name.toList()
+['marko']
+>>> g.V().outE().valueMap().with_(WithOptions.tokens).toList()
+[{<T.id: 1>: 9, <T.label: 4>: 'created', 'weight': 0.4}, {<T.id: 1>: 7, <T.label: 4>: 'knows', 'weight': 0.5}, {<T.id: 1>: 8, <T.label: 4>: 'knows', 'weight': 1.0}]
 ----
 
 NOTE: Many of the `TraversalStrategy` classes in Gremlin-Python are proxies to the respective strategy on
@@ -848,98 +896,34 @@
 Supporting link:https://en.wikipedia.org/wiki/Anonymous_function[anonymous functions] across languages is difficult as
 most languages do not support lambda introspection and thus, code analysis. In Gremlin-Python, a Gremlin lambda should
 be represented as a zero-arg callable that returns a string representation of the lambda expected for use in the
-traversal. The default lambda language is `gremlin-python` and can be changed via
-`gremlin_python.statics.default_lambda_language`. When the lambda is represented in `Bytecode` its language is encoded
-such that the remote connection host can infer which translator and ultimate execution engine to use.
+traversal. The lambda should be written as a `Gremlin-Groovy`string. When the lambda is represented in `Bytecode` its
+language is encoded such that the remote connection host can infer which translator and ultimate execution engine to
+use.
 
-[gremlin-python,modern]
+[source,python]
 ----
-g.V().out().map(lambda: "lambda x: len(x.get().value('name'))").sum().toList()                     <1>
-statics.default_lambda_language                                                                    <2>
-g.V().out().map(lambda: ("it.get().value('name').length()", 'gremlin-groovy')).sum().toList()      <3>
-statics.default_lambda_language = 'gremlin-groovy'                                                 <4>
-g.V().out().map(lambda: "it.get().value('name').length()").sum().toList()                          <5>
-g.V().out().map(lambda: ("lambda x: len(x.get().value('name'))", 'gremlin-python')).sum().toList() <6>
-statics.default_lambda_language = 'gremlin-python'                                                 <7>
-g.V().out().map(lambda: "x: len(x.get().value('name'))").sum().toList()                            <8>
+>>> g.V().out().map(lambda: "it.get().value('name').length()").sum().toList()
+[24]
 ----
 
-<1> A zero-arg lambda yields a string representation of a lambda in Gremlin-Python.
-<2> The default lambda language is currently Gremlin-Python.
-<3> A zero-arg lambda yields a 2-tuple where the second element is the language of the lambda (Gremlin-Groovy).
-<4> The default lambda language can be statically changed.
-<5> A zero-arg lambda yields a string representation of a closure in Gremlin-Groovy.
-<6> A zero-arg lambda yields a 2-tuple where the second element is the language of the lambda (Gremlin-Python).
-<7> The default lambda language is changed back to Gremlin-Python.
-<8> If the `lambda`-prefix is not provided, then it is appended automatically in order to give a more natural look to the expression.
-
 TIP: When running into situations where Groovy cannot properly discern a method signature based on the `Lambda`
 instance created, it will help to fully define the closure in the lambda expression - so rather than
 `lambda: ('it.get().value('name')','gremlin-groovy')`, prefer `lambda: ('x -> x.get().value('name'),'gremlin-groovy')`.
 
-WARNING: Jython support has been deprecated as for 3.3.10 and will be removed in 3.5.0. Gremlin-Python will at that
-point default to Groovy for lambda processing and Python lambdas will not be supported.
-
 Finally, Gremlin `Bytecode` that includes lambdas requires that the traversal be processed by the
 `ScriptEngine`. To avoid continued recompilation costs, it supports the encoding of bindings, which allow a remote
 engine to to cache traversals that will be reused over and over again save that some parameterization may change. Thus,
 instead of translating, compiling, and then executing each submitted bytecode, it is possible to simply execute.
 
-[gremlin-python,modern]
+[source,python]
 ----
-g.V(Bindings.of('id',1)).out('created').map(lambda: ("it.get().value('name').length()", 'gremlin-groovy')).sum().toList()
-g.V(Bindings.of('id',4)).out('created').map(lambda: ("it.get().value('name').length()", 'gremlin-groovy')).sum().toList()
+>>> g.V(Bindings.of('x',1)).out('created').map(lambda: "it.get().value('name').length()").sum().toList()
+[3]
+>>> g.V(Bindings.of('x',4)).out('created').map(lambda: "it.get().value('name').length()").sum().toList()
+[9]
 ----
 
-==== Native Python Lambdas
-
-To process lambdas in Python, the `GremlinJythonScriptEngine` must be enabled on the remote end. If that remote is
-Gremlin Server, then these instructions can help configuration it. As an example, the
-`conf/gremlin-server-modern-py.yaml` configuration maintains a `GremlinJythonScriptEngine`.
-
-[source,bash]
-----
-$ bin/gremlin-server.sh install org.apache.tinkerpop gremlin-python x.y.z
-$ bin/gremlin-server.sh conf/gremlin-server-modern-py.yaml
-[INFO] GremlinServer -
-       \,,,/
-       (o o)
----oOOo-(3)-oOOo---
-
-[INFO] GremlinServer - Configuring Gremlin Server from conf/gremlin-server-modern-py.yaml
-[INFO] MetricManager - Configured Metrics Slf4jReporter configured with interval=180000ms and loggerName=org.apache.tinkerpop.gremlin.server.Settings$Slf4jReporterMetrics
-[INFO] GraphManager - Graph [graph] was successfully configured via [conf/tinkergraph-empty.properties].
-[INFO] ServerGremlinExecutor - Initialized Gremlin thread pool.  Threads in pool named with pattern gremlin-*
-[INFO] ScriptEngines - Loaded gremlin-jython ScriptEngine
-[INFO] ScriptEngines - Loaded gremlin-python ScriptEngine
-[INFO] ScriptEngines - Loaded gremlin-groovy ScriptEngine
-[INFO] GremlinExecutor - Initialized gremlin-groovy ScriptEngine with scripts/generate-modern.groovy
-[INFO] ServerGremlinExecutor - Initialized GremlinExecutor and configured ScriptEngines.
-[INFO] ServerGremlinExecutor - A GraphTraversalSource is now bound to [g] with graphtraversalsource[tinkergraph[vertices:0 edges:0], standard]
-[INFO] OpLoader - Adding the standard OpProcessor.
-[INFO] OpLoader - Adding the session OpProcessor.
-[INFO] OpLoader - Adding the traversal OpProcessor.
-[INFO] TraversalOpProcessor - Initialized cache for TraversalOpProcessor with size 1000 and expiration time of 600000 ms
-[INFO] GremlinServer - Executing start up LifeCycleHook
-[INFO] Logger$info - Loading 'modern' graph data.
-[WARN] AbstractChannelizer - The org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0 serialization class is deprecated.
-[INFO] AbstractChannelizer - Configured application/vnd.gremlin-v3.0+gryo with org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0
-[WARN] AbstractChannelizer - The org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0 serialization class is deprecated.
-[INFO] AbstractChannelizer - Configured application/vnd.gremlin-v3.0+gryo-stringd with org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0
-[INFO] AbstractChannelizer - Configured application/vnd.gremlin-v3.0+json with org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV3d0
-[INFO] AbstractChannelizer - Configured application/json with org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV3d0
-[INFO] AbstractChannelizer - Configured application/vnd.graphbinary-v1.0 with org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1
-[INFO] AbstractChannelizer - Configured application/vnd.graphbinary-v1.0-stringd with org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1
-[INFO] GremlinServer$1 - Gremlin Server configured with worker thread pool of 1, gremlin pool of 8 and boss thread pool of 1.
-[INFO] GremlinServer$1 - Channel started at port 8182.
-----
-
-NOTE: The command to use `install` need only be executed once to gather `gremlin-python` dependencies into Gremlin Servers'
-path. Future starts of Gremlin Server will not require that command.
-
-WARNING: As explained throughout the documentation, when possible <<a-note-on-lambdas,avoid>> lambdas. If lambdas
-must be used, then consider submitting Groovy lambdas as opposed to Python-based ones. The `GremlinGroovyScriptEngine`
-is far more featured and performant than its Jython sibling and will likely yield better results.
+WARNING: As explained throughout the documentation, when possible <<a-note-on-lambdas,avoid>> lambdas.
 
 [[gremlin-python-scripts]]
 === Submitting Scripts
@@ -1104,11 +1088,14 @@
 Python supports meta-programming and operator overloading. There are three uses of these techniques in Gremlin-Python
 that makes traversals a bit more concise.
 
-[gremlin-python,modern]
+[source,python]
 ----
-g.V().both()[1:3].toList()
-g.V().both()[1].toList()
-g.V().both().name.toList()
+>>> g.V().both()[1:3].toList()
+[v[2], v[4]]
+>>> g.V().both()[1].toList()
+[v[2]]
+>>> g.V().both().name.toList()
+['lop', 'lop', 'lop', 'vadas', 'josh', 'josh', 'josh', 'marko', 'marko', 'marko', 'peter', 'ripple']
 ----
 
 [[gremlin-python-differences]]
@@ -1132,7 +1119,9 @@
 results within a collection across different languages. If a `Set` is needed then convert `List` results
 to `Set` manually.
 * Gremlin is capable of returning `Dictionary` results that use non-hashable keys (e.g. Dictionary as a key) and Python
-does not support that at a language level. Gremlin that returns such results will need to be re-written to avoid that.
+does not support that at a language level. Using GraphSON 3.0 or GraphBinary (after 3.5.0) makes it possible to return
+such results. In all other cases, Gremlin that returns such results will need to be re-written to avoid that sort of
+key.
 * The `subgraph()`-step is not supported by any variant that is not running on the Java Virtual Machine as there is
 no `Graph` instance to deserialize a result into on the client-side. A workaround is to replace the step with `store()`
 and then convert those results to something the client can use locally.
@@ -1141,14 +1130,14 @@
 === Application Examples
 
 The TinkerPop source code contains a simple Python script that shows a basic example of how gremlinpython works. It
-can be found in GitHub link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-python/src/main/jython/example.py[here]
+can be found in GitHub link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-python/src/main/python/example.py[here]
 and is designed to work best with a running <<gremlin-server,Gremlin Server>> configured with the default
 `conf/gremlin-server.yaml` file as included with the standard release packaging.
 
 [source,shell]
 ----
 pip install gremlinpython
-pip install tornado
+pip install aiohttp
 python example.py
 ----
 
@@ -1240,12 +1229,20 @@
 [[gremlin-dotnet-serialization]]
 === Serialization
 
-The Gremlin.Net driver uses by default GraphSON 3.0 but it is also possible to use GraphSON 2.0 which can be necessary
-when the server does not support GraphSON 3.0 yet:
+The Gremlin.Net driver uses by default GraphSON 3.0 but it is also possible to use another serialization format by passing a message serializer when creating the `GremlinClient`.
+
+GraphBinary can be configured like this:
 
 [source,csharp]
 ----
-include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=serialization]
+include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=serializationBinary]
+----
+
+and GraphSON 2.0 like this:
+
+[source,csharp]
+----
+include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=serializationGraphSon]
 ----
 
 [[gremlin-dotnet-strategies]]
@@ -1414,6 +1411,25 @@
 g.V().Repeat(__.Out()).Times(2).Values<string>("name");
 ----
 
+Gremlin allows for `Map` instances to include `null` keys, but `null` keys in C# `Dictionary` instances are not allowed.
+It is therefore necessary to rewrite a traversal such as:
+
+[source,javascript]
+----
+g.V().groupCount().by('age')
+----
+
+where "age" is not a valid key for all vertices in a way that will remove the need for a `null` to be returned.
+
+[source,javascript]
+----
+g.V().has('age').groupCount().by('age')
+g.V().hasLabel('person').groupCount().by('age')
+----
+
+Either of the above two options accomplishes the desired goal as both prevent `groupCount()` from having to process
+the possibility of `null`.
+
 anchor:gremlin-net-limitations[]
 [[gremlin-dotnet-limitations]]
 === Limitations
@@ -1691,6 +1707,41 @@
 
 *Steps* - <<from-step,from_()>>, <<in-step,in_()>>, <<with-step,with_()>>
 
+Gremlin allows for `Map` instances to include `null` keys, but `null` keys in Javascript have some interesting behavior
+as in:
+
+[source,text]
+----
+> var a = { null: 'something', 'b': 'else' };
+> JSON.stringify(a)
+'{"null":"something","b":"else"}'
+> JSON.parse(JSON.stringify(a))
+{ null: 'something', b: 'else' }
+> a[null]
+'something'
+> a['null']
+'something'
+----
+
+This behavior needs to be considered when using Gremlin to return such results. A typical situation where this might
+happen is with `group()` or `groupCount()` as in:
+
+[source,javascript]
+----
+g.V().groupCount().by('age')
+----
+
+where "age" is not a valid key for all vertices. In these cases, it will return `null` for that key and group on that.
+It may bet better in Javascript to filter away those vertices to avoid the return of `null` in the returned `Map`:
+
+[source,javascript]
+----
+g.V().has('age').groupCount().by('age')
+g.V().hasLabel('person').groupCount().by('age')
+----
+
+Either of the above two options accomplishes the desired goal as both prevent `groupCount()` from having to process
+the possibility of `null`.
 [[gremlin-javascript-limitations]]
 === Limitations
 
diff --git a/docs/src/reference/implementations-neo4j.asciidoc b/docs/src/reference/implementations-neo4j.asciidoc
index 75d7dae..6df1deb 100644
--- a/docs/src/reference/implementations-neo4j.asciidoc
+++ b/docs/src/reference/implementations-neo4j.asciidoc
@@ -25,11 +25,11 @@
    <version>x.y.z</version>
 </dependency>
 <!-- neo4j-tinkerpop-api-impl is NOT Apache 2 licensed - more information below -->
-<!-- supports Neo4j 3.2.3 -->
+<!-- supports Neo4j 3.4.11 -->
 <dependency>
   <groupId>org.neo4j</groupId>
   <artifactId>neo4j-tinkerpop-api-impl</artifactId>
-  <version>0.7-3.2.3</version>
+  <version>0.9-3.4.0</version>
 </dependency>
 ----
 
diff --git a/docs/src/reference/implementations-tinkergraph.asciidoc b/docs/src/reference/implementations-tinkergraph.asciidoc
index a5f49f0..bc69d58 100644
--- a/docs/src/reference/implementations-tinkergraph.asciidoc
+++ b/docs/src/reference/implementations-tinkergraph.asciidoc
@@ -39,7 +39,7 @@
 * Use TinkerGraph as a sandbox to develop and debug complex traversals by simulating data from a larger graph inside
 a TinkerGraph.
 
-Constructing a simple graph using TinkerGraph in Java8 is presented below:
+Constructing a simple graph using TinkerGraph in Java is presented below:
 
 [source,java]
 ----
@@ -121,6 +121,7 @@
 |gremlin.tinkergraph.edgeIdManager |The `IdManager` implementation to use for edges.
 |gremlin.tinkergraph.vertexPropertyIdManager |The `IdManager` implementation to use for vertex properties.
 |gremlin.tinkergraph.defaultVertexPropertyCardinality |The default `VertexProperty.Cardinality` to use when `Vertex.property(k,v)` is called.
+|gremlin.tinkergraph.allowNullPropertyValues |A boolean value that determines whether or not `null` property values are allowed and defaults to `true`.
 |gremlin.tinkergraph.graphLocation |The path and file name for where TinkerGraph should persist the graph data. If a
 value is specified here, the `gremlin.tinkergraph.graphFormat` should also be specified.  If this value is not
 included (default), then the graph will stay in-memory and not be loaded/persisted to disk.
diff --git a/docs/src/reference/intro.asciidoc b/docs/src/reference/intro.asciidoc
index aea28e6..6d6a1c7 100644
--- a/docs/src/reference/intro.asciidoc
+++ b/docs/src/reference/intro.asciidoc
@@ -424,11 +424,13 @@
 
 The first of these points is serialization. When Gremlin Server receives a request, the results must be serialized to
 the form requested by the client and then the client deserializes those into objects native to the language. TinkerPop
-has two such formats that it uses with link:https://tinkerpop.apache.org/docs/x.y.z/dev/io/#gryo[Gryo] and
-link:https://tinkerpop.apache.org/docs/x.y.z/dev/io/#graphson[GraphSON]. Gryo is a JVM-only format and thus carries the
-advantage that serializing and deserializing occurs on the classes native to the JVM on both the client and server side.
-As the client has full access to the same classes that the server does it basically has a full GTM on its own and
-therefore has the ability to do some slightly more advanced things.
+has three such formats that it uses with link:https://tinkerpop.apache.org/docs/x.y.z/dev/io/#graphbinary[GraphBinary],
+link:https://tinkerpop.apache.org/docs/x.y.z/dev/io/#gryo[Gryo] and
+link:https://tinkerpop.apache.org/docs/x.y.z/dev/io/#graphson[GraphSON]. Among these serialization formats, users
+should prefer GraphBinary as it combines the best features of both GraphSON and Gryo and it provides the most even
+user experience across different programming languages. There are areas however where this is not quite true, as
+Gremlin Language Variants don't have full GTMs present and therefore don't have the complete means to accomplish what
+a pure JVM solution would.
 
 A good example is the `subgraph()`-step which returns a `Graph` instance as its result. The subgraph returned from
 the server can be deserialized into an actual `Graph` instance on the client, which then means it is possible to
@@ -467,10 +469,11 @@
 [[basic-gremlin]]
 == Basic Gremlin
 
-The `GraphTraversalSource` is basically the connection to a graph instance. That graph instance might be
-<<connecting-embedded,embedded>>, hosted in <<connecting-gremlin-server,Gremlin Server>> or hosted in a
-<<connecting-rgp,RGP>>, but the `GraphTraversalSource` is agnostic to that. Assuming "g" is the `GraphTraversalSource`,
-getting data into the graph regardless of programming language or mode of operation is just some basic Gremlin:
+image:language-variants.png[width=300,float=right] The `GraphTraversalSource` is basically the connection to a graph
+instance. That graph instance might be <<connecting-embedded,embedded>>, hosted in
+<<connecting-gremlin-server,Gremlin Server>> or hosted in a <<connecting-rgp,RGP>>, but the `GraphTraversalSource` is
+agnostic to that. Assuming "g" is the `GraphTraversalSource`, getting data into the graph regardless of programming
+language or mode of operation is just some basic Gremlin:
 
 [gremlin-groovy]
 ----
diff --git a/docs/src/reference/the-graph.asciidoc b/docs/src/reference/the-graph.asciidoc
index ba0605e..fb4f21b 100644
--- a/docs/src/reference/the-graph.asciidoc
+++ b/docs/src/reference/the-graph.asciidoc
@@ -207,231 +207,6 @@
 WARNING: Attempting to set graph variables in a reference graph will not promote them to the remote graph. Typically,
 a reference graph has immutable features and will not support this features.
 
-[[transactions]]
-== Graph Transactions
-
-image:gremlin-coins.png[width=100,float=right] A link:http://en.wikipedia.org/wiki/Database_transaction[database transaction]
-represents a unit of work to execute against the database. Transactions in TinkerPop can be considered in several
-contexts: transactions for <<connecting-embedded,embedded graphs>> via the Graph API,
-transactions for <<connecting-gremlin-server,Gremlin Server>> and transactions within
-<<connecting-rgp,Remote Gremlin Providers>>. For those following recommended patterns, the concepts presented in the
-embedded section should generally be of little interest and are present mainly for reference. Utilizing those
-transactional features will greatly reduce the portability of an application's Gremlin code.
-
-[[tx-embedded]]
-=== Embedded
-
-When on the JVM using an <<connecting-embedded,embedded graph>>, there is considerable flexibility for working with
-transactions. With the Graph API, transactions are controlled by an implementation of the `Transaction` interface and
-that object can be obtained from the `Graph` interface using the `tx()` method.  It is important to note that the
-`Transaction` object does not represent a "transaction" itself.  It merely exposes the methods for working with
-transactions (e.g. committing, rolling back, etc).
-
-Most `Graph` implementations that `supportsTransactions` will implement an "automatic" `ThreadLocal` transaction,
-which means that when a read or write occurs after the `Graph` is instantiated, a transaction is automatically
-started within that thread.  There is no need to manually call a method to "create" or "start" a transaction.  Simply
-modify the graph as required and call `graph.tx().commit()` to apply changes or `graph.tx().rollback()` to undo them.
-When the next read or write action occurs against the graph, a new transaction will be started within that current
-thread of execution.
-
-When using transactions in this fashion, especially in web application (e.g. HTTP server), it is important to ensure
-that transactions do not leak from one request to the next.  In other words, unless a client is somehow bound via
-session to process every request on the same server thread, every request must be committed or rolled back at the end
-of the request.  By ensuring that the request encapsulates a transaction, it ensures that a future request processed
-on a server thread is starting in a fresh transactional state and will not have access to the remains of one from an
-earlier request. A good strategy is to rollback a transaction at the start of a request, so that if it so happens that
-a transactional leak does occur between requests somehow, a fresh transaction is assured by the fresh request.
-
-TIP: The `tx()` method is on the `Graph` interface, but it is also available on the `TraversalSource` spawned from a
-`Graph`.  Calls to `TraversalSource.tx()` are proxied through to the underlying `Graph` as a convenience.
-
-WARNING: TinkerPop provides for basic transaction control, however, like many aspects of TinkerPop, it is up to the
-graph system provider to choose the specific aspects of how their implementation will work and how it fits into the
-TinkerPop stack. Be sure to understand the transaction semantics of the specific graph implementation that is being
-utilized as it may present differing functionality than described here.
-
-==== Configuring
-
-Determining when a transaction starts is dependent upon the behavior assigned to the `Transaction`.  It is up to the
-`Graph` implementation to determine the default behavior and unless the implementation doesn't allow it, the behavior
-itself can be altered via these `Transaction` methods:
-
-[source,java]
-----
-public Transaction onReadWrite(Consumer<Transaction> consumer);
-
-public Transaction onClose(Consumer<Transaction> consumer);
-----
-
-Providing a `Consumer` function to `onReadWrite` allows definition of how a transaction starts when a read or a write
-occurs. `Transaction.READ_WRITE_BEHAVIOR` contains pre-defined `Consumer` functions to supply to the `onReadWrite`
-method.  It has two options:
-
-* `AUTO` - automatic transactions where the transaction is started implicitly to the read or write operation
-* `MANUAL` - manual transactions where it is up to the user to explicitly open a transaction, throwing an exception
-if the transaction is not open
-
-Providing a `Consumer` function to `onClose` allows configuration of how a transaction is handled when
-`Transaction.close()` is called.  `Transaction.CLOSE_BEHAVIOR` has several pre-defined options that can be supplied to
-this method:
-
-* `COMMIT` - automatically commit an open transaction
-* `ROLLBACK` - automatically rollback an open transaction
-* `MANUAL` - throw an exception if a transaction is open, forcing the user to explicitly close the transaction
-
-IMPORTANT: As transactions are `ThreadLocal` in nature, so are the transaction configurations for `onReadWrite` and
-`onClose`.
-
-Once there is an understanding for how transactions are configured, most of the rest of the `Transaction` interface
-is self-explanatory. Note that <<neo4j-gremlin,Neo4j-Gremlin>> is used for the examples to follow as TinkerGraph does
-not support transactions.
-
-[source,groovy]
-----
-gremlin> graph = Neo4jGraph.open('/tmp/neo4j')
-==>neo4jgraph[EmbeddedGraphDatabase [/tmp/neo4j]]
-gremlin> g = traversal().withEmbedded(graph)
-==>graphtraversalsource[neo4jgraph[community single [/tmp/neo4j]], standard]
-gremlin> graph.features()
-==>FEATURES
-> GraphFeatures
->-- Transactions: true  <1>
->-- Computer: false
->-- Persistence: true
-...
-gremlin> g.tx().onReadWrite(Transaction.READ_WRITE_BEHAVIOR.AUTO) <2>
-==>org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph$Neo4jTransaction@1c067c0d
-gremlin> g.addV("person").("name","stephen")  <3>
-==>v[0]
-gremlin> g.tx().commit() <4>
-==>null
-gremlin> g.tx().onReadWrite(Transaction.READ_WRITE_BEHAVIOR.MANUAL) <5>
-==>org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph$Neo4jTransaction@1c067c0d
-gremlin> g.tx().isOpen()
-==>false
-gremlin> g.addV("person").("name","marko") <6>
-Open a transaction before attempting to read/write the transaction
-gremlin> g.tx().open() <7>
-==>null
-gremlin> g.addV("person").("name","marko") <8>
-==>v[1]
-gremlin> g.tx().commit()
-==>null
-----
-
-<1> Check `features` to ensure that the graph supports transactions.
-<2> By default, `Neo4jGraph` is configured with "automatic" transactions, so it is set here for demonstration purposes only.
-<3> When the vertex is added, the transaction is automatically started.  From this point, more mutations can be staged
-or other read operations executed in the context of that open transaction.
-<4> Calling `commit` finalizes the transaction.
-<5> Change transaction behavior to require manual control.
-<6> Adding a vertex now results in failure because the transaction was not explicitly opened.
-<7> Explicitly open a transaction.
-<8> Adding a vertex now succeeds as the transaction was manually opened.
-
-NOTE: It may be important to consult the documentation of the `Graph` implementation you are using when it comes to the
-specifics of how transactions will behave.  TinkerPop allows some latitude in this area and implementations may not have
-the exact same behaviors and link:https://en.wikipedia.org/wiki/ACID[ACID] guarantees.
-
-==== Threaded Transactions
-
-Most `Graph` implementations that support transactions do so in a `ThreadLocal` manner, where the current transaction
-is bound to the current thread of execution. Consider the following example to demonstrate:
-
-[source,java]
-----
-GraphTraversalSource g = traversal().withEmbedded(graph);
-g.addV("person").("name","stephen").iterate();
-
-Thread t1 = new Thread(() -> {
-    g.addV("person").("name","josh").iterate();
-});
-
-Thread t2 = new Thread(() -> {
-    g.addV("person").("name","marko").iterate();
-});
-
-t1.start()
-t2.start()
-
-t1.join()
-t2.join()
-
-g.tx().commit();
-----
-
-The above code shows three vertices added to `graph` in three different threads: the current thread, `t1` and
-`t2`.  One might expect that by the time this body of code finished executing, that there would be three vertices
-persisted to the `Graph`.  However, given the `ThreadLocal` nature of transactions, there really were three separate
-transactions created in that body of code (i.e. one for each thread of execution) and the only one committed was the
-first call to `addV()` in the primary thread of execution.  The other two calls to that method within `t1` and `t2`
-were never committed and thus orphaned.
-
-A `Graph` that `supportsThreadedTransactions` is one that allows for a `Graph` to operate outside of that constraint,
-thus allowing multiple threads to operate within the same transaction.  Therefore, if there was a need to have three
-different threads operating within the same transaction, the above code could be re-written as follows:
-
-[source,java]
-----
-Graph threaded = graph.tx().createThreadedTx();
-GraphTraversalSource g = traversal().withEmbedded(graph);
-g.addV("person").("name","stephen").iterate();
-
-Thread t1 = new Thread(() -> {
-    threaded.addV("person").("name","josh").iterate();
-});
-
-Thread t2 = new Thread(() -> {
-    threaded.addV("person").("name","marko").iterate();
-});
-
-t1.start()
-t2.start()
-
-t1.join()
-t2.join()
-
-g.tx().commit();
-----
-
-In the above case, the call to `graph.tx().createThreadedTx()` creates a new `Graph` instance that is unbound from the
-`ThreadLocal` transaction, thus allowing each thread to operate on it in the same context.  In this case, there would
-be three separate vertices persisted to the `Graph`.
-
-[[tx-gremlin-server]]
-=== Gremlin Server
-
-The available capability for transactions with <<gremlin-server,Gremlin Server>> is dependent upon the method of
-interaction that is used. The preferred method for <<connecting-gremlin-server,interacting with Gremlin Server>>
-is via websockets and bytecode based requests. In this mode of operations each Gremlin traversal that is executed will
-be treated as a single transaction. Traversals that fail will have their transaction rolled back and successful
-iteration of a traversal will conclude with a transactional commit. How the graph hosted in Gremlin Server reacts to
-those commands is dependent on the graph chosen and it is therefore important to understand the transactional semantics
-of that graph when developing an application.
-
-Gremlin Server also has the option to accept Gremlin-based scripts. The scripting approach provides access to the
-Graph API and thus also the transactional model described in the <<tx-embedded,embedded>> section. Therefore a single
-script can have the ability to execute multiple transactions per request with complete control provided to the
-developer to commit or rollback transactions as needed.
-
-There are two methods for sending scripts to Gremlin Server: sessionless and session-based. With sessionless requests
-there will always be an attempt to close the transaction at the end of the request with a commit if there are no errors
-or a rollback if there is a failure. It is therefore unnecessary to close transactions manually within scripts
-themselves. By default, session-based requests do not have this quality. The transaction will be held open on the
-server until the user closes it manually. There is an option to have automatic transaction management for sessions.
-More information on this topic can be found in the <<considering-transactions,Considering Transactions>> Section and
-the <<sessions,Considering Sessions>> Section.
-
-[[tx-rgp]]
-=== Remote Gremlin Providers
-
-At this time, transactional patterns for Remote Gremlin Providers are largely in line with Gremlin Server. Most
-offer bytecode or script based sessionless requests, which have automatic transaction management, such that a
-successful traversal will commit on success and a failing traversal will rollback. As most of these RGPs do not
-expose a `Graph` instances, access to lower level transactional functions even in a sessionless fashion are not
-typically allowed. The nature of what a "transaction" means will be dependent on the RGP as is the case with any
-TinkerPop-enabled graph system, so it is important to consult that systems documentation for more details.
-
 == Namespace Conventions
 
 End users, <<implementations,graph system providers>>, <<graphcomputer,`GraphComputer`>> algorithm designers,
diff --git a/docs/src/reference/the-graphcomputer.asciidoc b/docs/src/reference/the-graphcomputer.asciidoc
index 25da35e..fece039 100644
--- a/docs/src/reference/the-graphcomputer.asciidoc
+++ b/docs/src/reference/the-graphcomputer.asciidoc
@@ -377,7 +377,12 @@
 ----
 g = traversal().withEmbedded(graph).withComputer()
 g.V().pageRank().elementMap()
-g.V().pageRank().by('pageRank').times(5).order().by('pageRank').elementMap()
+g.V().pageRank().
+        with(PageRank.propertyName, 'pageRank').
+        with(PageRank.times, 5).
+  order().
+    by('pageRank').
+  elementMap()
 ----
 
 [[peerpressurevertexprogram]]
@@ -399,8 +404,11 @@
 [gremlin-groovy,modern]
 ----
 g = traversal().withEmbedded(graph).withComputer()
-g.V().peerPressure().by('cluster').elementMap()
-g.V().peerPressure().by(outE('knows')).by('cluster').elementMap()
+g.V().peerPressure().with(PeerPressure.propertyName, 'cluster').elementMap()
+g.V().peerPressure().
+        with(PeerPressure.edges,outE('knows')).
+        with(PeerPressure.propertyName, 'cluster').
+  elementMap()
 ----
 
 [[connectedcomponentvertexprogram]]
diff --git a/docs/src/reference/the-traversal.asciidoc b/docs/src/reference/the-traversal.asciidoc
index aacd9d7..199d2f7 100644
--- a/docs/src/reference/the-traversal.asciidoc
+++ b/docs/src/reference/the-traversal.asciidoc
@@ -31,21 +31,12 @@
 `GraphTraversal` provides an interpretation of the graph data in terms of vertices, edges, etc. and thus, a graph
 traversal link:http://en.wikipedia.org/wiki/Domain-specific_language[DSL].
 
-IMPORTANT: The underlying `Step` implementations provided by TinkerPop should encompass most of the functionality
-required by a DSL author. It is important that DSL authors leverage the provided steps as then the common optimization
-and decoration strategies can reason on the underlying traversal sequence. If new steps are introduced, then common
-traversal strategies may not function properly.
-
-[[graph-traversal-steps]]
-== Graph Traversal Steps
-
 image::step-types.png[width=650]
 
 A `GraphTraversal<S,E>` is spawned from a `GraphTraversalSource`. It can also be spawned anonymously (i.e. empty)
 via `__`. A graph traversal is composed of an ordered list of steps. All the steps provided by `GraphTraversal`
 inherit from the more general forms diagrammed above. A list of all the steps (and their descriptions) are provided
 in the TinkerPop link:https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html[GraphTraversal JavaDoc].
-The following subsections will demonstrate the GraphTraversal steps using the <<gremlin-console,Gremlin Console>>.
 
 IMPORTANT: The basics for starting a traversal are described in <<the-graph-process,The Graph Process>> section as
 well as in the link:https://tinkerpop.apache.org/docs/current/tutorials/getting-started/[Getting Started] tutorial.
@@ -56,6 +47,341 @@
 when using anonymous traversals. For example, `in` and `as` are reserved keywords in Groovy, therefore you must use
 the verbose syntax `+__.in()+` and `+__.as()+` to avoid collisions.
 
+IMPORTANT: The underlying `Step` implementations provided by TinkerPop should encompass most of the functionality
+required by a DSL author. It is important that DSL authors leverage the provided steps as then the common optimization
+and decoration strategies can reason on the underlying traversal sequence. If new steps are introduced, then common
+traversal strategies may not function properly.
+
+[[transactions]]
+== Traversal Transactions
+
+image:gremlin-coins.png[width=100,float=right] A link:http://en.wikipedia.org/wiki/Database_transaction[database transaction]
+represents a unit of work to execute against the database. A traversals unit of work is affected by usage convention
+(i.e. the method of <<connecting-gremlin, connecting>>) and the graph provider's transaction model. Without diving
+deeply into different conventions and models the most general and recommended approach to working with transactions is
+demonstrated as follows:
+
+[source,java]
+----
+GraphTraversalSource g = traversal().withEmbedded(graph);
+// or
+GraphTraversalSource g = traversal().withRemote(conn);
+
+Transaction tx = g.tx();
+
+// spawn a GraphTraversalSource from the Transaction. Traversals spawned
+// from gtx will be essentially be bound to tx
+GraphTraversalSource gtx = tx.begin();
+try {
+    gtx.addV('person').iterate();
+    gtx.addV('software').iterate();
+
+    tx.commit();
+} catch (Exception ex) {
+    tx.rollback();
+}
+----
+
+The above example is straightforward and represents a good starting point for discussing the nuances of transactions
+in relation to the usage convention and graph provider caveats alluded to earlier.
+
+Focusing on remote contexts first, note that it is still possible to issue traversals from `g`, but those will have a
+transaction scope outside of `gtx` and will simply `commit()` on the server if successfully executed or `rollback()`
+on the server otherwise (i.e. one traversal is one transaction). Each isolated transaction will require its own
+`Transaction` object. Multiple `begin()` calls on the same `Transaction` object will produce `GraphTraversalSource`
+instances that are bound to the same transaction, therefore:
+
+[source,java]
+----
+GraphTraversalSource g = traversal().withRemote(conn);
+Transaction tx1 = g.tx();
+Transaction tx2 = g.tx();
+
+// both gtx1a and gtx1b will be bound to the same transaction
+GraphTraversalSource gtx1a = tx1.begin();
+GraphTraversalSource gtx1b = tx1.begin();
+
+// g and gtx2 will not have knowledge of what happens in tx1
+GraphTraversalSource gtx2 = tx2.begin();
+----
+
+In remote cases, `GraphTraversalSource` instances spawned from `begin()` are safe to use in multiple threads though
+they on the server side they will be processed serially as they arrive. The default behavior of `close()` on a
+`Transaction` for remote cases is to `commit()`, so the following re-write of the earlier example is also valid:
+
+[source,java]
+----
+// note here that we dispense with creating a Transaction object and
+// simply spawn the gtx in a more inline fashion
+GraphTraversalSource gtx = g.tx().begin();
+try {
+    gtx.addV('person').iterate();
+    gtx.addV('software').iterate();
+    gtx.close();
+} catch (Exception ex) {
+    tx.rollback();
+}
+----
+
+In embedded cases, that initial recommended model for defining transactions holds, but users have more options here
+on deeper inspection. For embedded use cases (and perhaps even in configuration of a graph instance in Gremlin Server),
+the type of `Transaction` object that is returned from `g.tx()` is an important indicator as to the features of that
+graph's transaction model. In most cases, inspection of that object will indicate an instance that derives from the
+`AbstractThreadLocalTransaction` class, which means that the transaction is bound to the current thread and therefore
+all traversals that execute within that thread are tied to that transaction.
+
+A `ThreadLocal` transaction differs then from the remote case described before because technically any traversal
+spawned from `g` or from a `Transaction` will fall under the same transaction scope. As a result, it is wise, when
+trying to write context agnostic Gremlin, to follow the more rigid conventions of the initial example.
+
+The sub-sections that follow offer a bit more insight into each of the usage contexts.
+
+[[tx-embedded]]
+=== Embedded
+
+When on the JVM using an <<connecting-embedded,embedded graph>>, there is considerable flexibility for working with
+transactions. With the Graph API, transactions are controlled by an implementation of the `Transaction` interface and
+that object can be obtained from the `Graph` interface using the `tx()` method.  It is important to note that the
+`Transaction` object does not represent a "transaction" itself.  It merely exposes the methods for working with
+transactions (e.g. committing, rolling back, etc).
+
+Most `Graph` implementations that `supportsTransactions` will implement an "automatic" `ThreadLocal` transaction,
+which means that when a read or write occurs after the `Graph` is instantiated, a transaction is automatically
+started within that thread.  There is no need to manually call a method to "create" or "start" a transaction.  Simply
+modify the graph as required and call `graph.tx().commit()` to apply changes or `graph.tx().rollback()` to undo them.
+When the next read or write action occurs against the graph, a new transaction will be started within that current
+thread of execution.
+
+When using transactions in this fashion, especially in web application (e.g. HTTP server), it is important to ensure
+that transactions do not leak from one request to the next.  In other words, unless a client is somehow bound via
+session to process every request on the same server thread, every request must be committed or rolled back at the end
+of the request.  By ensuring that the request encapsulates a transaction, it ensures that a future request processed
+on a server thread is starting in a fresh transactional state and will not have access to the remains of one from an
+earlier request. A good strategy is to rollback a transaction at the start of a request, so that if it so happens that
+a transactional leak does occur between requests somehow, a fresh transaction is assured by the fresh request.
+
+TIP: The `tx()` method is on the `Graph` interface, but it is also available on the `TraversalSource` spawned from a
+`Graph`.  Calls to `TraversalSource.tx()` are proxied through to the underlying `Graph` as a convenience.
+
+TIP: Some graphs may throw an exception that implements `TemporaryException`. In this case, this marker interface is
+designed to inform the client that it may choose to retry the operation at a later time for possible success.
+
+WARNING: TinkerPop provides for basic transaction control, however, like many aspects of TinkerPop, it is up to the
+graph system provider to choose the specific aspects of how their implementation will work and how it fits into the
+TinkerPop stack. Be sure to understand the transaction semantics of the specific graph implementation that is being
+utilized as it may present differing functionality than described here.
+
+==== Configuring
+
+Determining when a transaction starts is dependent upon the behavior assigned to the `Transaction`.  It is up to the
+`Graph` implementation to determine the default behavior and unless the implementation doesn't allow it, the behavior
+itself can be altered via these `Transaction` methods:
+
+[source,java]
+----
+public Transaction onReadWrite(Consumer<Transaction> consumer);
+
+public Transaction onClose(Consumer<Transaction> consumer);
+----
+
+Providing a `Consumer` function to `onReadWrite` allows definition of how a transaction starts when a read or a write
+occurs. `Transaction.READ_WRITE_BEHAVIOR` contains pre-defined `Consumer` functions to supply to the `onReadWrite`
+method.  It has two options:
+
+* `AUTO` - automatic transactions where the transaction is started implicitly to the read or write operation
+* `MANUAL` - manual transactions where it is up to the user to explicitly open a transaction, throwing an exception
+if the transaction is not open
+
+Providing a `Consumer` function to `onClose` allows configuration of how a transaction is handled when
+`Transaction.close()` is called.  `Transaction.CLOSE_BEHAVIOR` has several pre-defined options that can be supplied to
+this method:
+
+* `COMMIT` - automatically commit an open transaction
+* `ROLLBACK` - automatically rollback an open transaction
+* `MANUAL` - throw an exception if a transaction is open, forcing the user to explicitly close the transaction
+
+IMPORTANT: As transactions are `ThreadLocal` in nature, so are the transaction configurations for `onReadWrite` and
+`onClose`.
+
+Once there is an understanding for how transactions are configured, most of the rest of the `Transaction` interface
+is self-explanatory. Note that <<neo4j-gremlin,Neo4j-Gremlin>> is used for the examples to follow as TinkerGraph does
+not support transactions.
+
+IMPORTANT: The following example is meant to demonstrate specific use of `ThreadLocal` transactions and is at odds
+with the more generalized transaction convention that is recommended for both embedded and remote contexts. Please be
+sure to understand the preferred approach described at in the <<transactions,Traversal Transactions Section>> before
+using this method.
+
+[source,groovy]
+----
+gremlin> graph = Neo4jGraph.open('/tmp/neo4j')
+==>neo4jgraph[EmbeddedGraphDatabase [/tmp/neo4j]]
+gremlin> g = traversal().withEmbedded(graph)
+==>graphtraversalsource[neo4jgraph[community single [/tmp/neo4j]], standard]
+gremlin> graph.features()
+==>FEATURES
+> GraphFeatures
+>-- Transactions: true  <1>
+>-- Computer: false
+>-- Persistence: true
+...
+gremlin> g.tx().onReadWrite(Transaction.READ_WRITE_BEHAVIOR.AUTO) <2>
+==>org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph$Neo4jTransaction@1c067c0d
+gremlin> g.addV("person").("name","stephen")  <3>
+==>v[0]
+gremlin> g.tx().commit() <4>
+==>null
+gremlin> g.tx().onReadWrite(Transaction.READ_WRITE_BEHAVIOR.MANUAL) <5>
+==>org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph$Neo4jTransaction@1c067c0d
+gremlin> g.tx().isOpen()
+==>false
+gremlin> g.addV("person").("name","marko") <6>
+Open a transaction before attempting to read/write the transaction
+gremlin> g.tx().open() <7>
+==>null
+gremlin> g.addV("person").("name","marko") <8>
+==>v[1]
+gremlin> g.tx().commit()
+==>null
+----
+
+<1> Check `features` to ensure that the graph supports transactions.
+<2> By default, `Neo4jGraph` is configured with "automatic" transactions, so it is set here for demonstration purposes only.
+<3> When the vertex is added, the transaction is automatically started.  From this point, more mutations can be staged
+or other read operations executed in the context of that open transaction.
+<4> Calling `commit` finalizes the transaction.
+<5> Change transaction behavior to require manual control.
+<6> Adding a vertex now results in failure because the transaction was not explicitly opened.
+<7> Explicitly open a transaction.
+<8> Adding a vertex now succeeds as the transaction was manually opened.
+
+NOTE: It may be important to consult the documentation of the `Graph` implementation you are using when it comes to the
+specifics of how transactions will behave.  TinkerPop allows some latitude in this area and implementations may not have
+the exact same behaviors and link:https://en.wikipedia.org/wiki/ACID[ACID] guarantees.
+
+[[tx-gremlin-server]]
+=== Gremlin Server
+
+The available capability for transactions with <<gremlin-server,Gremlin Server>> is dependent upon the method of
+interaction that is used. The preferred method for <<connecting-gremlin-server,interacting with Gremlin Server>>
+is via websockets and bytecode based requests. The start of the <<transactions,Transactions Section>> describes this
+approach in detail with examples.
+
+Gremlin Server also has the option to accept Gremlin-based scripts. The scripting approach provides access to the
+Graph API and thus also the transactional model described in the <<tx-embedded,embedded>> section. Therefore a single
+script can have the ability to execute multiple transactions per request with complete control provided to the
+developer to commit or rollback transactions as needed.
+
+There are two methods for sending scripts to Gremlin Server: sessionless and session-based. With sessionless requests
+there will always be an attempt to close the transaction at the end of the request with a commit if there are no errors
+or a rollback if there is a failure. It is therefore unnecessary to close transactions manually within scripts
+themselves. By default, session-based requests do not have this quality. The transaction will be held open on the
+server until the user closes it manually. There is an option to have automatic transaction management for sessions.
+More information on this topic can be found in the <<considering-transactions,Considering Transactions>> Section and
+the <<sessions,Considering Sessions>> Section.
+
+[[tx-rgp]]
+=== Remote Gremlin Providers
+
+At this time, transactional patterns for Remote Gremlin Providers are largely in line with Gremlin Server. As most of
+RGPs do not expose a `Graph` instance, access to lower level transactional functions even in a sessionless fashion are
+not typically permitted. The nature of what a "transaction" means will be dependent on the RGP as is the case with any
+TinkerPop-enabled graph system, so it is important to consult that systems documentation for more details.
+
+[[configuration-steps]]
+== Configuration Steps
+
+Many of the methods on the `GraphTraversalSource` are meant to configure the source for usage. These configuration
+affect the manner in which a traversals are spawned from it. Configuration methods can be identified by their names
+with make use of "with" as a prefix:
+
+[[configuration-steps-with]]
+=== With Configuration
+
+The `with()` configuration adds arbitrary data to a `TraversalSource` which can then be used by graph providers as
+configuration options for a traversal execution. This configuration is similar to <<with-step,with()>>-modulator which
+has similar functionality when applied to an individual step.
+
+[source,groovy]
+----
+g.with('providerDefinedVariable', 0.33).V()
+----
+
+The `0.33` value for the "providerDefinedVariable" will be bound to each traversal spawned that way. Consult the
+graph system being used to determine if any such configuration options are available.
+
+[[configuration-steps-withbulk]]
+=== WithBulk Configuration
+
+The `withBulk()` configuration allows for control of bulking operations. This value is `true` by default allowing for
+normal <<barrier-step,bulking>> operations, but when set to `false`, introduces a subtle change in that behavior as
+shown in examples in <<sack-step,sack()-step>>.
+
+[[configuration-steps-withcomputer]]
+=== WithComputer Configuration
+
+The `withComputer()` configuration adds a `Computer` that will be used to process the traversal and is necessary for
+OLAP based processing and steps that require that processing. See <<sparkgraphcomputer,examples>> related to
+`SparkGraphComputer` or see examples in the computer required steps, like <<pagerank-step,pageRank()>> or
+<<shortestpath-shortestPath()>>.
+
+[[configuration-steps-withsack]]
+=== WithSack Configuration
+
+The `withSack()` configuration adds a "sack" that can be accessed by traversals spawned from this source. This
+functionality is shown in more detail in the examples for (<<sack-step,sack()>>)-step.
+
+[[configuration-steps-withsideeffect]]
+=== WithSideEffect Configuration
+
+The `withSideEffect()` configuration adds an arbitrary `Object` to traversals spawned from this source which can be
+accessed as a side-effect given the supplied key.
+
+[gremlin-groovy,modern]
+----
+g.withSideEffect('x',['dog','cat','fish']).
+  V().has('person','name','marko').select('x').unfold()
+----
+
+More practical examples can be found in other examples elsewhere in the documentation. The `math()`-step
+<<math-step,example>> and the `where()`-step <<where-step,example>> should both be helpful in examining this
+configuration step more closely.
+
+[[configuration-steps-withstrategies]]
+=== WithStrategies Configuration
+
+The `withStrategies()` configuration allows inclusion of additional `TraversalStrategy` instances to be applied to
+any traversals spawned from the configured source. Please see the <<traversal-strategy,Traversal Strategy Section>>
+for more details on how this configuration works.
+
+[[configuration-steps-withoutstrategies]]
+=== WithoutStrategies Configuration
+
+The `withoutStrategies()` configuration removes a particular `TraversalStrategy` from those to be applied to traversals
+spawned from the configured source. Please see the <<traversal-strategy,Traversal Strategy Section>> for more details
+on how this configuration works.
+
+[[start-steps]]
+== Start Steps
+
+Not all steps are capable of starting a `GraphTraversal`. Only those steps on the `GraphTraversalSource` can do that.
+Many of the methods on `GraphTraversalSource` are actually for its <<configuration-steps,configuration>> and start
+steps should not be confused with those.
+
+Spawn steps, which actually yield a traversal, typically match the names of existing steps:
+
+* `addE()` - Adds an `Edge` to start the traversal (<<addedge-step, example>>).
+* `addV()` - Adds a `Vertex` to start the traversal (<<addvertex-step, example>>).
+* `E()` - Reads edges from the graph to start the traversal (<<graph-step, example>>).
+* `inject()` - Inserts arbitrary objects to start the traversal (<<inject-step, example>>).
+* `V()` - Reads vertices from the graph to start the traversal (<<graph-step, example>>).
+
+[[graph-traversal-steps]]
+== Graph Traversal Steps
+
+Gremlin steps are chained together to produce the actual traversal and are triggered by way of <<start-steps,start steps>>
+on the `GraphTraversalSource`.
+
 [[general-steps]]
 === General Steps
 
@@ -140,36 +466,6 @@
 <2> The same operation, but using the traversal representing of `branch()`.
 <3> The more specific boolean-based `choose()`-step is implemented as a `branch()`.
 
-[[start-steps]]
-=== Start Steps
-
-Not all steps are capable of starting a `GraphTraversal`. Only those steps on the `GraphTraversalSource` can do that.
-Many of the methods on `GraphTraversalSource` are actually for its configuration. From that configured object, it is
-then possible to use start steps to spawn a `GraphTraversal`.
-
-Configuration methods can be identified by their names with make use of "with" as a prefix:
-
-* `with()` - Adds arbitrary configuration options which can be used by graph providers as configuration options.
-* `withBulk()` - This value is `true` by default allowing for normal <<barrier-step,bulking>> operations, but when set
-to `false`, introduces a subtle change in that behavior as shown in examples in <<sack-step,sack()-step>>.
-* `withComputer()` - Adds a `Computer` that will be used to process the traversal (<<sparkgraphcomputer,example>>).
-* `withSack()` - Adds a "sack" that can be accessed by traversals spawned from this source (<<sack-step,example>>).
-* `withSideEffect()` - Adds an arbitrary `Object` to traversals spawned from this source which can be accessed as a
-side-effect given the supplied key (<<math-step,example>>).
-* `withStrategies()` - Includes additional `TraversalStrategy` instances to be applied to any traversals spawned from
-the configured source (<<readonlystrategy, example>>).
-* `withPath()`
-* `withoutStrategies()` - Removes a particular `TraversalStrategy` from those to be applied to traversals spawned from
-the configured source.
-
-Spawn steps, which actually yield a traversal, typically match the names of existing steps:
-
-* `addE()` - Adds an `Edge` to start the traversal (<<addedge-step, example>>).
-* `addV()` - Adds a `Vertex` to start the traversal (<<addvertex-step, example>>).
-* `E()` - Reads edges from the graph to start the traversal (<<graph-step, example>>).
-* `inject()` - Inserts arbitrary objects to start the traversal (<<inject-step, example>>).
-* `V()` - Reads vertices from the graph to start the traversal (<<graph-step, example>>).
-
 [[terminal-steps]]
 === Terminal Steps
 
@@ -240,10 +536,10 @@
       addE('friendlyCollaborator').from('a').to('b').
         property(id,23).property('project',select('c').values('name')) <5>
 g.E(23).valueMap()
-marko = g.V().has('name','marko').next()
-peter = g.V().has('name','peter').next()
-g.V(marko).addE('knows').to(peter) <6>
-g.addE('knows').from(marko).to(peter) <7>
+vMarko = g.V().has('name','marko').next()
+vPeter = g.V().has('name','peter').next()
+g.V(vMarko).addE('knows').to(vPeter) <6>
+g.addE('knows').from(vMarko).to(vPeter) <7>
 ----
 
 <1> Add a co-developer edge with a year-property between marko and his collaborators.
@@ -809,9 +1105,12 @@
 g.V().values('lang')
 g.V().values('lang').dedup()
 g.V(1).repeat(bothE('created').dedup().otherV()).emit().path() <1>
+g.V().bothE().properties().dedup() <2>
 ----
 
 <1> Traverse all `created` edges, but don't touch any edge twice.
+<2> Note that `Property` instances will compare on key and value, whereas a `VertexProperty` will also include its
+element as it is a first-class citizen.
 
 If a by-step modulation is provided to `dedup()`, then the object is processed accordingly prior to determining if it
 has been seen or not.
@@ -2110,14 +2409,16 @@
 [[pagerank-step]]
 === PageRank Step
 
-The `pageRank()`-step (*map*/*sideEffect*) calculates link:http://en.wikipedia.org/wiki/PageRank[PageRank] using <<pagerankvertexprogram,`PageRankVertexProgram`>>.
+The `pageRank()`-step (*map*/*sideEffect*) calculates link:http://en.wikipedia.org/wiki/PageRank[PageRank] using
+<<pagerankvertexprogram,`PageRankVertexProgram`>>.
 
-IMPORTANT: The `pageRank()`-step is a `VertexComputing`-step and as such, can only be used against a graph that supports `GraphComputer` (OLAP).
+IMPORTANT: The `pageRank()`-step is a `VertexComputing`-step and as such, can only be used against a graph that
+supports `GraphComputer` (OLAP).
 
 [gremlin-groovy,modern]
 ----
 g = traversal().withEmbedded(graph).withComputer()
-g.V().pageRank().by('pageRank').values('pageRank')
+g.V().pageRank().with(PageRank.propertyName, 'friendRank').values('pageRank')
 g.V().hasLabel('person').
   pageRank().
     with(PageRank.edges, __.outE('knows')).
@@ -2129,7 +2430,8 @@
 Note the use of the `with()` modulating step which provides configuration options to the algorithm. It takes
 configuration keys from the `PageRank` and is automatically imported to the Gremlin Console.
 
-The <<explain-step,`explain()`>>-step can be used to understand how the traversal is compiled into multiple `GraphComputer` jobs.
+The <<explain-step,`explain()`>>-step can be used to understand how the traversal is compiled into multiple
+`GraphComputer` jobs.
 
 [gremlin-groovy,modern]
 ----
@@ -2252,7 +2554,7 @@
 [gremlin-groovy,modern]
 ----
 g = traversal().withEmbedded(graph).withComputer()
-g.V().peerPressure().by('cluster').values('cluster')
+g.V().peerPressure().with(PeerPressure.propertyName, 'cluster').values('cluster')
 g.V().hasLabel('person').
   peerPressure().
     with(PeerPressure.propertyName, 'cluster').
@@ -2717,15 +3019,17 @@
 
 [gremlin-groovy,modern]
 ----
-g.V(1).repeat(local(
-         bothE().sample(1).by('weight').otherV()
-       )).times(5)
-g.V(1).repeat(local(
-         bothE().sample(1).by('weight').otherV()
-       )).times(5).path()
-g.V(1).repeat(local(
-         bothE().sample(1).by('weight').otherV()
-       )).times(10).path()
+g.V(1).
+  repeat(local(bothE().sample(1).by('weight').otherV())).
+    times(5)
+g.V(1).
+  repeat(local(bothE().sample(1).by('weight').otherV())).
+    times(5).
+  path()
+g.V(1).
+  repeat(local(bothE().sample(1).by('weight').otherV())).
+    times(10).
+  path()
 ----
 
 As a clarification, note that in the above example `local()` is not strictly required as it only does the random walk
@@ -3799,6 +4103,33 @@
 
 NOTE: The <<explain-step,`explain()`>>-step shows the user how each registered strategy mutates the traversal.
 
+TinkerPop ships with a generous number of `TraversalStrategy` definitions, most of which are applied implicitly when
+executing a gremlin traversal. Users and providers can add `TraversalStrategy` definitions for particular needs. The
+following sections detail how traversal strategies are applied and defined and describe a collection of traversal
+strategies that are generally useful to end-users.
+
+=== Application
+
+One can explicitly add or remove `TraversalStrategy` strategies on the `GraphTraversalSource` with the `withStrategies()`
+and `withoutStrategies()` <<start-steps, start steps>>, see the <<readonlystrategy, ReadOnlyStrategy>> and the
+<<barrier-step, barrier() step>> for examples. End users typically do this as part of issuing a gremlin traversal, either
+on a locally opened graph or a remotely accessed graph. However, when configuring Gremlin Server, traversal strategies
+can also be applied on exposed `GraphTraversalSource` instances and as part of an `Authorizer` implementation, see
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#authorization[Gremlin Server Authorization].
+Therefore, one should keep the following in mind when modifying the list of `TraversalStrategy` strategies:
+
+* A `TraversalStrategy` added to the traversal can be removed again later on. An example is the
+`conf/gremlin-server-modern-readonly.yaml` file from the Gremlin Server distribution, which applies the `ReadOnlyStrategy`
+to the `GraphTraversalSource` that remote clients can connect to. However, a remote client can remove it on its turn
+by applying the `withoutStrategies()` step with the `ReadOnlyStrategy`.
+* When a `TraversalStrategy` of a particular type is added, it replaces any instances of its type that exist prior to
+it. Multiple instances of a `TraversalStrategy` can therefore not be registered and their functionality is no way
+merged automatically. Therefore, if there is a particular strategy registered whose functionality needs to be changed
+it is important to either find and modify the existing instance or construct a new one copying the options to keep
+from the old to the new instance.
+
+=== Definition
+
 A simple `OptimizationStrategy` is the `IdentityRemovalStrategy`.
 
 [source,java]
@@ -3940,9 +4271,6 @@
 <8> `PathRetractionStrategy` will remove paths from the traversers and increase the likelihood of bulking as path data is not required after `select('b')`.
 <9> `AdjacentToIncidentStrategy` will turn `out()` into `outE()` to increase data access locality.
 
-A collection of useful `DecorationStrategy` strategies are provided with TinkerPop and are generally useful to
-end-users.  The following sub-sections detail these strategies:
-
 === ElementIdStrategy
 
 `ElementIdStrategy` provides control over element identifiers. Some Graph implementations, such as TinkerGraph,
@@ -4031,6 +4359,7 @@
 may also not behave as "snapshots" at the time of their creation as they are "live" references to actual database
 elements.
 
+[[partitionstrategy]]
 === PartitionStrategy
 
 image::partition-graph.png[width=325]
@@ -4087,6 +4416,45 @@
 Display stack trace? [yN]
 ----
 
+=== SeedStrategy
+
+There are number of components of the Gremlin language that, by design, can produce non-deterministic results:
+
+* <<coin-step,coin()>>
+* <<order-step,order()>> when `Order.shuffle` is used
+* <<sample-step,sample()>>
+
+To get these steps to return deterministic results, `SeedStrategy` allows assignment of a seed value to the `Random`
+operations of the steps. The following example demonstrates the random nature of `shuffle`:
+
+[gremlin-groovy,modern]
+----
+g.V().values('name').fold().order(local).by(shuffle)
+g.V().values('name').fold().order(local).by(shuffle)
+g.V().values('name').fold().order(local).by(shuffle)
+g.V().values('name').fold().order(local).by(shuffle)
+g.V().values('name').fold().order(local).by(shuffle)
+----
+
+With `SeedStrategy` in place, however, the same order is applied each time:
+
+[gremlin-groovy,modern]
+----
+seedStrategy = new SeedStrategy(999998L)
+g.withStrategies(seedStrategy).V().values('name').fold().order(local).by(shuffle)
+g.withStrategies(seedStrategy).V().values('name').fold().order(local).by(shuffle)
+g.withStrategies(seedStrategy).V().values('name').fold().order(local).by(shuffle)
+g.withStrategies(seedStrategy).V().values('name').fold().order(local).by(shuffle)
+g.withStrategies(seedStrategy).V().values('name').fold().order(local).by(shuffle)
+----
+
+IMPORTANT: `SeedStrategy` only makes specific steps behave in a deterministic fashion and does not necessarily make
+the entire traversal deterministic itself. If the underlying graph database or processing engine happens to not
+guarantee iteration order, then it is possible that the final result of the traversal will appear to be
+non-deterministic. In these cases, it would be necessary to enforce a deterministic iteration with `order()` prior to
+these steps that make use of randomness to return results.
+
+[[subraphstrategy]]
 === SubgraphStrategy
 
 `SubgraphStrategy` is similar to `PartitionStrategy` in that it constrains a `Traversal` to certain vertices, edges,
@@ -4131,6 +4499,24 @@
     by('name')
 ----
 
+=== VertexProgramDenyStrategy
+
+Like the `ReadOnlyStrategy`, the `VertexProgramDenyStrategy` denies the execution of specific traversals. A `Traversal`
+that has the `VertexProgramDenyStrategy` applied will throw an `IllegalStateException` if it uses the
+`withComputer()` step. This `TraversalStrategy` can be useful for configuring `GraphTraversalSource` instances in
+Gremlin Server with the `ScriptFileGremlinPlugin`.
+
+[source,text]
+----
+gremlin> oltpOnly = g.withStrategies(VertexProgramDenyStrategy.instance())
+==>graphtraversalsource[tinkergraph[vertices:5 edges:7], standard]
+gremlin> oltpOnly.withComputer().V().elementMap()
+The TraversalSource does not allow the use of a GraphComputer
+Type ':help' or ':h' for help.
+Display stack trace? [yN]
+----
+
+
 [[dsl]]
 == Domain Specific Languages
 
@@ -4206,11 +4592,11 @@
 [width="100%",cols="<,^,^,^,^,^",options="header"]
 |=========================================================
 | |Java |Groovy |Javascript |.NET |Python
-|*Java* | |X | | |X
-|*Groovy* | |X | | |X
-|*Javascript* | |X | | |
-|*.NET* | | | | |
-|*Python*  | | | | |
+|*Java* |- |X |X |X |X
+|*Groovy* | |X |X | |X
+|*Javascript* | |X |- | |
+|*.NET* | | | |- |
+|*Python*  | |X | | |-
 |=========================================================
 
 Each programming language has its own API for translation, but the pattern is quite similar from one to the next:
@@ -4222,19 +4608,28 @@
 ----
 // gremlin-core module
 import org.apache.tinkerpop.gremlin.process.traversal.translator.*;
+
 GraphTraversalSource g = ...;
 Traversal<Vertex,Integer> t = g.V().has("person","name","marko").
                                 where(in("knows")).
                                 values("age").
-                                map(Lambda.Function("it.get() + 1");
+                                map(Lambda.function("it.get() + 1"));
 
 Translator.ScriptTranslator groovyTranslator = GroovyTranslator.of("g");
-System.out.println(groovyTranslator.translate(t);
+System.out.println(groovyTranslator.translate(t).getScript());
 // OUTPUT: g.V().has("person","name","marko").where(__.in("knows")).values("age").map({it.get() + 1})
 
+Translator.ScriptTranslator dotnetTranslator = DotNetTranslator.of("g");
+System.out.println(dotnetTranslator.translate(t).getScript());
+// OUTPUT: g.V().Has("person","name","marko").Where(__.In("knows")).Values<object>("age").Map<object>(Lambda.Groovy("it.get() + 1"))
+
 Translator.ScriptTranslator pythonTranslator = PythonTranslator.of("g");
-System.out.println(pythonTranslator.translate(t);
+System.out.println(pythonTranslator.translate(t).getScript());
 // OUTPUT: g.V().has('person','name','marko').where(__.in_('knows')).age.map(lambda: "it.get() + 1")
+
+Translator.ScriptTranslator javascriptTranslator = JavascriptTranslator.of("g");
+System.out.println(javascriptTranslator.translate(t).getScript());
+// OUTPUT: g.V().has("person","name","marko").where(__.in_("knows")).values("age").map(() => "it.get() + 1")
 ----
 [source,javascript]
 ----
@@ -4248,4 +4643,37 @@
 console.log(translator.translate(t));
 // OUTPUT: g.V().has('person','name','marko').where(__.in('knows')).values('age')
 ----
+[source,python]
+----
+from gremlin_python.process.translator import *
+
+g = ...
+t = (g.V().has('person','name','marko').
+          where(__.in_("knows")).
+          values("age"))
+
+# Groovy
+translator = Translator().of('g');
+print(translator.translate(t.bytecode));
+# OUTPUT: g.V().has('person','name','marko').where(__.in('knows')).values('age') 
+----
+
+The JVM-based translator has the added option of parameter extraction, where the translation process will attempt to
+identify opportunities to generate an output that would replace constant values with parameters. The parameters would
+then be extracted and returned as part of the `Script` object:
+
+[source,java]
+----
+Traversal<Vertex,Integer> t = g.V().has("person","name","marko").
+                                where(__.in("knows")).
+                                values("age");
+// specify true to attempt parameter extraction
+Translator.ScriptTranslator translator = GroovyTranslator.of("g", true);
+Script s = translator.translate(t);
+System.out.println(s.getScript());
+// OUTPUT: g.V().has(_args_0,_args_1,_args_2).where(__.in(_args_3)).values(_args_4)
+System.out.println(s.parameters);
+// OUTPUT: Optional[{_args_0=person, _args_2=marko, _args_1=name, _args_4=age, _args_3=knows}]
+----
+
 
diff --git a/docs/src/tutorials/gremlin-language-variants/index.asciidoc b/docs/src/tutorials/gremlin-language-variants/index.asciidoc
index ef8cd36..d26544c 100644
--- a/docs/src/tutorials/gremlin-language-variants/index.asciidoc
+++ b/docs/src/tutorials/gremlin-language-variants/index.asciidoc
@@ -14,599 +14,11 @@
 See the License for the specific language governing permissions and
 limitations under the License.
 ////
-
 image::apache-tinkerpop-logo.png[width=500,link="https://tinkerpop.apache.org"]
 
 *x.y.z*
 
-== Gremlin Language Variants
-
-Gremlin is an embeddable query language that can be represented using the constructs of a host programming language.
-Any programming language that supports link:https://en.wikipedia.org/wiki/Function_composition[function composition]
-(e.g. fluent chaining) and link:https://en.wikipedia.org/wiki/Nested_function[function nesting] (e.g. call stacks)
-can support Gremlin. Nearly every modern programming language is capable of meeting both requirements.
-With Gremlin, the distinction between a programming language and a query language is not as large as they
-have historically been. For instance, with Gremlin-Java, the developer is able to have their application code and their
-graph database queries at the same level of abstraction -- both written in Java. A simple example is presented below
-where the `MyApplication` Java class contains both application-level and database-level code written in Java.
-
 image::gremlin-house-of-mirrors.png[width=1024]
 
-WARNING: This is an advanced tutorial intended for experts knowledgeable in Gremlin in particular and TinkerPop in
-general. Moreover, the audience should understand advanced programming language concepts such as reflection,
-meta-programming, source code generation, and virtual machines.
-
-[source,java]
-----
-public class MyApplication {
-
-  public static void run(String[] args) {
-
-    // assumes args[0] is a configuration file location
-    Graph graph = GraphFactory.open(args[0]);
-    GraphTraversalSource g = traversal().withEmbedded(graph);
-
-    // assumes that args[1] and args[2] are range boundaries
-    Iterator<Map<String,Double>> result =
-      g.V().hasLabel("product").
-        order().by("unitPrice", asc).
-        range(Integer.valueOf(args[1]), Integer.valueOf(args[2])).
-        valueMap("name", "unitPrice")
-
-    while(result.hasNext()) {
-      Map<String,Double> map = result.next();
-      System.out.println(map.get("name") + " " + map.get("unitPrice"));
-    }
-  }
-}
-----
-
-In query languages like link:https://en.wikipedia.org/wiki/SQL[SQL], the user must construct a string representation of
-their query and submit it to the database for evaluation. This is because SQL cannot be expressed in Java as they use
-fundamentally different constructs in their expression. The same example above is presented below using SQL and the
-link:https://en.wikipedia.org/wiki/Java_Database_Connectivity[JDBC] interface. The take home point is that Gremlin does
-not exist outside the programming language in which it will be used. Gremlin was designed to be able to be
-embedded in any modern programming language and thus, always free from the complexities of string manipulation as seen
-in other database and analytics query languages.
-
-[source,java]
-----
-public class MyApplication {
-
-  public static void run(final String[] args) {
-
-    // assumes args[0] is a URI to the database
-    Connection connection = DriverManager.getConnection(args[0])
-    Statement statement = connection.createStatement();
-
-    // assumes that args[1] and args[2] are range boundaries
-    ResultSet result = statement.executeQuery(
-      "SELECT Products.ProductName, Products.UnitPrice \n" +
-      "  FROM (SELECT ROW_NUMBER() \n" +
-      "                   OVER ( \n" +
-      "                     ORDER BY UnitPrice) AS [ROW_NUMBER], \n" +
-      "                 ProductID \n" +
-      "            FROM Products) AS SortedProducts \n" +
-      "      INNER JOIN Products \n" +
-      "              ON Products.ProductID = SortedProducts.ProductID \n" +
-      "   WHERE [ROW_NUMBER] BETWEEN " + args[1] + " AND " + args[2] + " \n" +
-      "ORDER BY [ROW_NUMBER]"
-
-    while(result.hasNext()) {
-      result.next();
-      System.out.println(result.getString("Products.ProductName") + " " + result.getDouble("Products.UnitPrice"));
-    }
-  }
-}
-----
-
-The purpose of this tutorial is to explain how to develop a _Gremlin language variant_. That is, for those developers
-who are interested in supporting Gremlin in their native language and there currently does not exist a (good) Gremlin
-variant in their language, they can develop one for the Apache TinkerPop community (and their language community in
-general). In this tutorial, link:https://www.python.org/[Python] will serve as the host language and two typical
-implementation models will be presented.
-
-1. <<using-jython-and-the-jvm,**Using Jython and the JVM**>>: This is perhaps the easiest way to produce a Gremlin
-language variant. With link:https://www.jcp.org/en/jsr/detail?id=223[JSR-223], any language compiler written for the JVM
-can directly access the JVM and any of its libraries (including Gremlin-Java).
-
-2. <<using-python-and-remoteconnection,**Using Python and GremlinServer**>>: This model requires that there exist a Python
-class that mimics Gremlin-Java's `GraphTraversal` API. With each method call of this Python class, Gremlin `Bytecode` is
-generated which is ultimately translated into a Gremlin variant that can execute the traversal (e.g. Gremlin-Java).
-
-IMPORTANT: Apache TinkerPop's Gremlin-Java is considered the idiomatic, standard implementation of Gremlin.
-Any Gremlin language variant, regardless of the implementation model chosen, **must**, within the constraints of the
-host language, be in 1-to-1 correspondence with Gremlin-Java. This ensures that language variants are collectively
-consistent and easily leveraged by anyone versed in Gremlin.
-
-IMPORTANT: The "Gremlin-Python" presented in this tutorial is basic and provided to show the primary techniques used to
-construct a Gremlin language variant. Apache TinkerPop distributes with a full fledged
-link:https://tinkerpop.apache.org/docs/x.y.z/reference/#gremlin-python[Gremlin-Python] variant that uses many of the
-techniques presented in this tutorial.
-
-[[language-drivers-vs-language-variants]]
-== Language Drivers vs. Language Variants
-
-Before discussing how to implement a Gremlin language variant in Python, it is necessary to understand two concepts
-related to Gremlin language development. There is a difference between a _language driver_ and a _language variant_
-and it is important that these two concepts (and their respective implementations) remain separate.
-
-=== Language Drivers
-
-image:language-drivers.png[width=375,float=right] A Gremlin language driver is a software library that is able to
-communicate with a TinkerPop-enabled graph system whether directly via the JVM or indirectly via
-link:https://tinkerpop.apache.org/docs/x.y.z/reference/#connecting-gremlin-server[Gremlin Server] Gremlin Server or some
-other link:https://tinkerpop.apache.org/docs/x.y.z/reference/#connecting-rgp[RemoteConnection] enabled graph system.
-Language drivers are responsible for submitting Gremlin traversals to a TinkerPop-enabled graph system and
-returning results to the developer that are within the developer's language's type system.
-For instance, resultant doubles should be coerced to floats in Python.
-
-This tutorial is not about language drivers, but about language variants. Moreover, community libraries should make
-this distinction clear and **should not** develop libraries that serve both roles. Language drivers will be useful to
-a collection of Gremlin variants within a language community -- able to support `GraphTraversal`-variants as well as
-also other link:https://en.wikipedia.org/wiki/Domain-specific_language[DSL]-variants (e.g. `SocialTraversal`).
-
-NOTE: `GraphTraversal` is a particular Gremlin domain-specific language (link:https://en.wikipedia.org/wiki/Domain-specific_language[DSL]),
-albeit the most popular and foundational DSL. If another DSL is created, then the same techniques discussed in this
-tutorial for `GraphTraversal` apply to `XXXTraversal`.
-
-=== Language Variants
-
-image:language-variants.png[width=375,float=right] A Gremlin language variant is a software library that allows a
-developer to write a Gremlin traversal within their native programming language. The language variant is responsible
-for creating Gremlin `Bytecode` that will ultimately be translated and compiled to a `Traversal` by a
-TinkerPop-enabled graph system.
-
-Every language variant, regardless of the implementation details, will have to account for the four core concepts below:
-
-1. `Graph` (**data**): The source of the graph data to be traversed and the interface which enables the creation of a
-`GraphTraversalSource` (via `traversal().withEmbedded(graph)`).
-
-2. `GraphTraversalSource` (**compiler**): This is the typical `g` reference. A `GraphTraversalSource` maintains the
-`withXXX()`-strategy methods as well as the "traversal spawn"-methods such as `V()`, `E()`, `addV()`, etc.
-A traversal source's registered `TraversalStrategies` determine how the submitted traversal will be ultimately
-evaluated.
-
-3. `GraphTraversal` (**function composition**): A graph traversal maintains the computational steps such as `out()`, `groupCount()`,
-`match()`, etc. This fluent interface supports method chaining and thus, a linear "left-to-right" representation of a
-traversal/query.
-
-4. `__` (**function nesting**) : The anonymous traversal class is used for passing a traversal as an argument to a
-parent step. For example, in `+repeat(__.out())+`, `+__.out()+` is an anonymous traversal passed to the traversal parent
-`repeat()`. Anonymous traversals enable the "top-to-bottom" representation of a traversal.
-
-5. `Bytecode` (**language agnostic encoding**): The source and traversal steps and their arguments are encoded in a
-language agnostic representation called Gremlin bytecode. This representation is a nested list of the form
-`[step,[args*]]*`.
-
-Both `GraphTraversal` and `+__+` define the structure of the Gremlin language. Gremlin is a _two-dimensional language_
-supporting linear, nested step sequences. Historically, many Gremlin language variants have failed to make the
-distinctions above clear and in doing so, either complicate their implementations or yield variants that are not in
-1-to-1 correspondence with Gremlin-Java. By keeping these concepts clear when designing a language variant, the
-construction of the Gremlin bytecode representation is easy.
-
-IMPORTANT: The term "Gremlin-Java" denotes the language that is defined by `GraphTraversalSource`, `GraphTraversal`,
-and `__`. These three classes exist in `org.apache.tinkerpop.gremlin.process.traversal.dsl.graph` and form the
-definitive representation of the Gremlin traversal language.
-
-== Gremlin-Jython and Gremlin-Python
-
-[[using-jython-and-the-jvm]]
-=== Using Jython and the JVM
-
-image:jython-logo.png[width=200,float=left,link="http://www.jython.org/"] link:http://www.jython.org/[Jython] provides a
-link:https://www.jcp.org/en/jsr/detail?id=223[JSR-223] `ScriptEngine` implementation that enables the evaluation of
-Python on the link:https://en.wikipedia.org/wiki/Java_virtual_machine[Java virtual machine]. In other words, Jython's
-virtual machine is not the standard link:https://wiki.python.org/moin/CPython[CPython] reference implementation
-distributed with most operating systems, but instead the JVM. The benefit of Jython is that Python code and classes
-can easily interact with the Java API and any Java packages on the `CLASSPATH`. In general, any JSR-223 Gremlin language
-variant is trivial to "implement."
-
-[source,python]
-----
-Jython 2.7.0 (default:9987c746f838, Apr 29 2015, 02:25:11)
-[Java HotSpot(TM) 64-Bit Server VM (Oracle Corporation)] on java1.8.0_40
-Type "help", "copyright", "credits" or "license" for more information.
->>> import sys
-# this list is longer than displayed, including all jars in lib/, not just Apache TinkerPop jars
-# there is probably a more convenient way of importing jars in Jython though, at the time of writing, no better solution was found.
->>> sys.path.append("/usr/local/apache-gremlin-console-x.y.z-standalone/lib/gremlin-console-x.y.z.jar")
->>> sys.path.append("/usr/local/apache-gremlin-console-x.y.z-standalone/lib/gremlin-core-x.y.z.jar")
->>> sys.path.append("/usr/local/apache-gremlin-console-x.y.z-standalone/lib/gremlin-driver-x.y.z.jar")
->>> sys.path.append("/usr/local/apache-gremlin-console-x.y.z-standalone/lib/gremlin-shaded-x.y.z.jar")
->>> sys.path.append("/usr/local/apache-gremlin-console-x.y.z-standalone/ext/tinkergraph-gremlin/lib/tinkergraph-gremlin-x.y.z.jar")
-# import Java classes
->>> from org.apache.tinkerpop.gremlin.tinkergraph.structure import TinkerFactory
->>> from org.apache.tinkerpop.gremlin.process.traversal.dsl.graph import __
->>> from org.apache.tinkerpop.gremlin.process.traversal import *
->>> from org.apache.tinkerpop.gremlin.structure import *
-# create the toy "modern" graph and spawn a GraphTraversalSource
->>> graph = TinkerFactory.createModern()
->>> g = graph.traversal()
-# The Jython shell does not automatically iterate Iterators like the GremlinConsole
->>> g.V().hasLabel("person").out("knows").out("created")
-[GraphStep(vertex,[]), HasStep([~label.eq(person)]), VertexStep(OUT,[knows],vertex), VertexStep(OUT,[created],vertex)]
-# toList() will do the iteration and return the results as a list
->>> g.V().hasLabel("person").out("knows").out("created").toList()
-[v[5], v[3]]
->>> g.V().repeat(__.out()).times(2).values("name").toList()
-[ripple, lop]
-# results can be interacted with using Python
->>> g.V().repeat(__.out()).times(2).values("name").toList()[0]
-u'ripple'
->>> g.V().repeat(__.out()).times(2).values("name").toList()[0][0:3].upper()
-u'RIP'
->>>
-----
-
-Most every JSR-223 `ScriptEngine` language will allow the developer to immediately interact with `GraphTraversal`.
-The benefit of this model is that nearly every major programming language has a respective `ScriptEngine`:
-link:https://en.wikipedia.org/wiki/Nashorn_(JavaScript_engine)[JavaScript], link:http://groovy-lang.org/[Groovy],
-link:http://www.scala-lang.org/[Scala], Lisp (link:https://clojure.org/[Clojure]), link:http://jruby.org/[Ruby], etc. A
-list of implementations is provided link:https://en.wikipedia.org/wiki/List_of_JVM_languages[here].
-
-==== Traversal Wrappers
-
-While it is possible to simply interact with Java classes in a `ScriptEngine` implementation, such Gremlin language
-variants will not leverage the unique features of the host language. It is for this reason that JVM-based language
-variants such as link:https://github.com/mpollmeier/gremlin-scala[Gremlin-Scala] were developed. Scala provides many
-syntax niceties not available in Java. To leverage these niceties, Gremlin-Scala "wraps" `GraphTraversal` in order to
-provide Scala-idiomatic extensions. Another example is Apache TinkerPop's Gremlin-Groovy which does the same via the
-link:https://tinkerpop.apache.org/docs/x.y.z/reference/#sugar-plugin[Sugar plugin], but uses
-link:http://groovy-lang.org/metaprogramming.html[meta-programming] instead of object wrapping, where "behind the
-scenes," Groovy meta-programming is doing object wrapping.
-
-The Jython example below uses Python meta-programming to add functionality to `GraphTraversal`. In particular, the
-`+__getitem__+` and `+__getattr__+` "magic methods" are leveraged.
-
-[source,python]
-----
-def getitem_bypass(self, index):
-  if isinstance(index,int):
-    return self.range(index,index+1)
-  elif isinstance(index,slice):
-    return self.range(index.start,index.stop)
-  else:
-    return TypeError('Index must be int or slice')");
-GraphTraversal.__getitem__ = getitem_bypass
-GraphTraversal.__getattr__ = lambda self, key: self.values(key)
-----
-
-The two methods `+__getitem__+` and `+__getattr__+` support Python _slicing_ and _object attribute interception_,
-respectively. In this way, the host language is able to use its native constructs in a meaningful way within a
-Gremlin traversal.
-
-IMPORTANT: Gremlin-Java serves as the standard/default representation of the Gremlin traversal language. Any Gremlin
-language variant **must** provide all the same functionality (methods) as `GraphTraversal`, but **can** extend it
-with host language specific constructs. This means that the extensions **must** compile to `GraphTraversal`-specific
-steps. A Gremlin language variant **should not** add steps/methods that do not exist in `GraphTraversal`. If an extension
-is desired, the language variant designer should submit a proposal to link:https://tinkerpop.apache.org[Apache TinkerPop]
-to have the extension added to a future release of Gremlin.
-
-[[using-python-and-remoteconnection]]
-=== Using Python and RemoteConnection
-
-image:python-logo.png[width=125,float=left,link="https://www.python.org/"] The JVM is a powerful piece of technology
-that has, over the years, become a meeting ground for developers from numerous language communities. However, not all
-applications will use the JVM. Given that Apache TinkerPop is a Java-framework, there must be a way for two different
-virtual machines to communicate traversals and their results. This section presents the second Gremlin language
-variant implementation model which does just that.
-
-NOTE: Apache TinkerPop is a JVM-based graph computing framework. Most graph databases and processors today are built
-on the JVM. This makes it easy for these graph system providers to implement Apache TinkerPop. However, TinkerPop is more
-than its graph API and tools -- it is also the Gremlin traversal machine and language. While Apache's Gremlin traversal
-machine was written for the JVM, its constructs are simple and can/should be ported to other VMs for those graph systems
-that are not JVM-based. A theoretical review of the concepts behind the Gremlin traversal machine is provided in
-link:http://arxiv.org/abs/1508.03843[this article].
-
-This section's Gremlin language variant design model does not leverage the JVM directly. Instead, it constructs a
-`Bytecode` representation of a `Traversal` that will ultimately be evaluated by `RemoteConnection` (e.g. GremlinServer).
-It is up to the language variant designer to choose a _language driver_ to use for submitting the generated bytecode and
-coercing its results. The language driver is the means by which, for this example, the CPython
-VM communicates with the JVM.
-
-[source,bash]
-----
-# sudo easy_install pip
-$ pip install gremlinpython
-----
-
-The Groovy source code below uses Java reflection to generate a Python class that is in 1-to-1 correspondence with
-Gremlin-Java.
-
-[source,groovy]
-----
-class GraphTraversalSourceGenerator {
-
-    public static void create(final String graphTraversalSourceFile) {
-
-        final StringBuilder pythonClass = new StringBuilder()
-
-        pythonClass.append("from .traversal import Traversal\n")
-        pythonClass.append("from .traversal import TraversalStrategies\n")
-        pythonClass.append("from .traversal import Bytecode\n")
-        pythonClass.append("from ..driver.remote_connection import RemoteStrategy\n")
-        pythonClass.append("from .. import statics\n\n")
-
-//////////////////////////
-// GraphTraversalSource //
-//////////////////////////
-        pythonClass.append(
-                """class GraphTraversalSource(object):
-  def __init__(self, graph, traversal_strategies, bytecode=None):
-    self.graph = graph
-    self.traversal_strategies = traversal_strategies
-    if bytecode is None:
-      bytecode = Bytecode()
-    self.bytecode = bytecode
-  def __repr__(self):
-    return "graphtraversalsource[" + str(self.graph) + "]"
-""")
-        GraphTraversalSource.getMethods(). // SOURCE STEPS
-                findAll { GraphTraversalSource.class.equals(it.returnType) }.
-                findAll {
-                    !it.name.equals("clone") &&
-                            !it.name.equals(TraversalSource.Symbols.withRemote)
-                }.
-                collect { SymbolHelper.toPython(it.name) }.
-                unique().
-                sort { a, b -> a <=> b }.
-                forEach { method ->
-                    pythonClass.append(
-                            """  def ${method}(self, *args):
-    source = GraphTraversalSource(self.graph, TraversalStrategies(self.traversal_strategies), Bytecode(self.bytecode))
-    source.bytecode.add_source("${SymbolHelper.toJava(method)}", *args)
-    return source
-""")
-                }
-        pythonClass.append(
-                """  def withRemote(self, remote_connection):
-    source = GraphTraversalSource(self.graph, TraversalStrategies(self.traversal_strategies), Bytecode(self.bytecode))
-    source.traversal_strategies.add_strategies([RemoteStrategy(remote_connection)])
-    return source
-""")
-        GraphTraversalSource.getMethods(). // SPAWN STEPS
-                findAll { GraphTraversal.class.equals(it.returnType) }.
-                collect { SymbolHelper.toPython(it.name) }.
-                unique().
-                sort { a, b -> a <=> b }.
-                forEach { method ->
-                    pythonClass.append(
-                            """  def ${method}(self, *args):
-    traversal = GraphTraversal(self.graph, self.traversal_strategies, Bytecode(self.bytecode))
-    traversal.bytecode.add_step("${SymbolHelper.toJava(method)}", *args)
-    return traversal
-""")
-                }
-        pythonClass.append("\n\n")
-
-////////////////////
-// GraphTraversal //
-////////////////////
-        pythonClass.append(
-                """class GraphTraversal(Traversal):
-  def __init__(self, graph, traversal_strategies, bytecode):
-    Traversal.__init__(self, graph, traversal_strategies, bytecode)
-  def __getitem__(self, index):
-    if isinstance(index, int):
-        return self.range(index, index + 1)
-    elif isinstance(index, slice):
-        return self.range(index.start, index.stop)
-    else:
-        raise TypeError("Index must be int or slice")
-  def __getattr__(self, key):
-    return self.values(key)
-""")
-        GraphTraversal.getMethods().
-                findAll { GraphTraversal.class.equals(it.returnType) }.
-                findAll { !it.name.equals("clone") }.
-                collect { SymbolHelper.toPython(it.name) }.
-                unique().
-                sort { a, b -> a <=> b }.
-                forEach { method ->
-                    pythonClass.append(
-                            """  def ${method}(self, *args):
-    self.bytecode.add_step("${SymbolHelper.toJava(method)}", *args)
-    return self
-""")
-                };
-        pythonClass.append("\n\n")
-
-////////////////////////
-// AnonymousTraversal //
-////////////////////////
-        pythonClass.append("class __(object):\n");
-        __.class.getMethods().
-                findAll { GraphTraversal.class.equals(it.returnType) }.
-                findAll { Modifier.isStatic(it.getModifiers()) }.
-                collect { SymbolHelper.toPython(it.name) }.
-                unique().
-                sort { a, b -> a <=> b }.
-                forEach { method ->
-                    pythonClass.append(
-                            """  @staticmethod
-  def ${method}(*args):
-    return GraphTraversal(None, None, Bytecode()).${method}(*args)
-""")
-                };
-        pythonClass.append("\n\n")
-        // add to gremlin.python.statics
-        __.class.getMethods().
-                findAll { GraphTraversal.class.equals(it.returnType) }.
-                findAll { Modifier.isStatic(it.getModifiers()) }.
-                findAll { !it.name.equals("__") }.
-                collect { SymbolHelper.toPython(it.name) }.
-                unique().
-                sort { a, b -> a <=> b }.
-                forEach {
-                    pythonClass.append("def ${it}(*args):\n").append("      return __.${it}(*args)\n\n")
-                    pythonClass.append("statics.add_static('${it}', ${it})\n\n")
-                }
-        pythonClass.append("\n\n")
-
-// save to a python file
-        final File file = new File(graphTraversalSourceFile);
-        file.delete()
-        pythonClass.eachLine { file.append(it + "\n") }
-    }
-}
-----
-
-When the above Groovy script is evaluated (e.g. in GremlinConsole), **Gremlin-Python** is born. The generated Python
-file is similar to the one available at
-link:https://github.com/apache/tinkerpop/blob/x.y.z/gremlin-python/src/main/jython/gremlin_python/process/graph_traversal.py[graph_traversal.py].
-It is important to note that there is a bit more to Gremlin-Python in that there also exists Python implementations
-of `TraversalStrategies`, `Traversal`, `Bytecode`, etc. Please review the full implementation of Gremlin-Python
-link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-python/src/main/jython/gremlin_python[here].
-
-NOTE: In practice, TinkerPop uses the Groovy's `GStringTemplateEngine` to help with the code generation task described
-above and automates that generation as part of the standard build with Maven using the `gmavenplus-plugin`. See the
-`gremlin-python` link:https://github.com/apache/tinkerpop/blob/x.y.z/gremlin-python/pom.xml[pom.xml] for more details.
-
-Of particular importance is Gremlin-Python's implementation of `Bytecode`.
-
-[source,python]
-----
-class Bytecode(object):
-  def __init__(self, bytecode=None):
-    self.source_instructions = []
-    self.step_instructions = []
-    self.bindings = {}
-    if bytecode is not None:
-      self.source_instructions = list(bytecode.source_instructions)
-      self.step_instructions = list(bytecode.step_instructions)
-
-  def add_source(self, source_name, *args):
-    newArgs = ()
-    for arg in args:
-      newArgs = newArgs + (self.__convertArgument(arg),)
-    self.source_instructions.append((source_name, newArgs))
-    return
-
-  def add_step(self, step_name, *args):
-    newArgs = ()
-    for arg in args:
-      newArgs = newArgs + (self.__convertArgument(arg),)
-    self.step_instructions.append((step_name, newArgs))
-    return
-
-  def __convertArgument(self,arg):
-    if isinstance(arg, Traversal):
-      self.bindings.update(arg.bytecode.bindings)
-      return arg.bytecode
-    elif isinstance(arg, tuple) and 2 == len(arg) and isinstance(arg[0], str):
-      self.bindings[arg[0]] = arg[1]
-      return Binding(arg[0],arg[1])
-    else:
-      return arg
-----
-
-As `GraphTraversalSource` and `GraphTraversal` are manipulated, the step-by-step instructions are written to `Bytecode`.
-This bytecode is simply a list of lists. For instance, `g.V(1).repeat(out('knows').hasLabel('person')).times(2).name` has
-the `Bytecode` form:
-
-[source,json]
-----
-[
- ["V", [1]],
- ["repeat", [[
-   ["out", ["knows"]]
-   ["hasLabel", ["person"]]]]]
- ["times", [2]]
- ["values", ["name"]]
-]
-----
-
-This nested list representation is ultimately converted by the language variant into link:https://tinkerpop.apache.org/docs/x.y.z/reference/#graphson[GraphSON]
-for serialization to a `RemoteConnection` such as GremlinServer.
-
-[source,bash]
-----
-$ bin/gremlin-server.sh install org.apache.tinkerpop gremlin-python x.y.z
-$ bin/gremlin-server.sh conf/gremlin-server-modern-py.yaml
-[INFO] GremlinServer -
-       \,,,/
-       (o o)
----oOOo-(3)-oOOo---
-
-[INFO] GremlinServer - Configuring Gremlin Server from conf/gremlin-server-modern-py.yaml
-[INFO] MetricManager - Configured Metrics Slf4jReporter configured with interval=180000ms and loggerName=org.apache.tinkerpop.gremlin.server.Settings$Slf4jReporterMetrics
-[INFO] GraphManager - Graph [graph] was successfully configured via [conf/tinkergraph-empty.properties].
-[INFO] ServerGremlinExecutor - Initialized Gremlin thread pool.  Threads in pool named with pattern gremlin-*
-[INFO] ServerGremlinExecutor - Initialized GremlinExecutor and configured ScriptEngines.
-[INFO] Logger - 56 attributes loaded from 90 stream(s) in 21ms, 56 saved, 1150 ignored: ["Ant-Version", "Archiver-Version", "Bnd-LastModified", "Boot-Class-Path", "Build-Jdk", "Build-Version", "Built-By", "Bundle-Activator", "Bundle-BuddyPolicy", "Bundle-ClassPath", "Bundle-Description", "Bundle-DocURL", "Bundle-License", "Bundle-ManifestVersion", "Bundle-Name", "Bundle-RequiredExecutionEnvironment", "Bundle-SymbolicName", "Bundle-Vendor", "Bundle-Version", "Can-Redefine-Classes", "Created-By", "DynamicImport-Package", "Eclipse-BuddyPolicy", "Export-Package", "Extension-Name", "Extension-name", "Fragment-Host", "Gremlin-Plugin-Dependencies", "Ignore-Package", "Implementation-Build", "Implementation-Title", "Implementation-URL", "Implementation-Vendor", "Implementation-Vendor-Id", "Implementation-Version", "Import-Package", "Include-Resource", "JCabi-Build", "JCabi-Date", "JCabi-Version", "Main-Class", "Main-class", "Manifest-Version", "Originally-Created-By", "Package", "Private-Package", "Require-Capability", "Specification-Title", "Specification-Vendor", "Specification-Version", "Tool", "Url", "X-Compile-Source-JDK", "X-Compile-Target-JDK", "hash", "version"]
-[INFO] ServerGremlinExecutor - A GraphTraversalSource is now bound to [g] with graphtraversalsource[tinkergraph[vertices:0 edges:0], standard]
-[INFO] OpLoader - Adding the standard OpProcessor.
-[INFO] OpLoader - Adding the session OpProcessor.
-[INFO] OpLoader - Adding the traversal OpProcessor.
-[INFO] TraversalOpProcessor - Initialized cache for TraversalOpProcessor with size 1000 and expiration time of 600000 ms
-[INFO] GremlinServer - Executing start up LifeCycleHook
-[INFO] Logger$info - Executed once at startup of Gremlin Server.
-[WARN] AbstractChannelizer - The org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0 serialization class is deprecated.
-[INFO] AbstractChannelizer - Configured application/vnd.gremlin-v3.0+gryo with org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0
-[WARN] AbstractChannelizer - The org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0 serialization class is deprecated.
-[INFO] AbstractChannelizer - Configured application/vnd.gremlin-v3.0+gryo-stringd with org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0
-[INFO] AbstractChannelizer - Configured application/vnd.gremlin-v3.0+json with org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV3d0
-[INFO] AbstractChannelizer - Configured application/json with org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV3d0
-[INFO] AbstractChannelizer - Configured application/vnd.graphbinary-v1.0 with org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1
-[INFO] AbstractChannelizer - Configured application/vnd.graphbinary-v1.0-stringd with org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1
-[INFO] GremlinServer$1 - Gremlin Server configured with worker thread pool of 1, gremlin pool of 8 and boss thread pool of 1.
-[INFO] GremlinServer$1 - Channel started at port 8182.
-----
-
-Within the CPython console, it is possible to evaluate the following.
-
-[source,python]
-----
-Python 2.7.2 (default, Oct 11 2012, 20:14:37)
-[GCC 4.2.1 Compatible Apple Clang 4.0 (tags/Apple/clang-418.0.60)] on darwin
-Type "help", "copyright", "credits" or "license" for more information.
->>> from gremlin_python import statics
->>> from gremlin_python.structure.graph import Graph
->>> from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection
-# loading statics enables __.out() to be out() and P.gt() to be gt()
->>> statics.load_statics(globals())
->>> graph = Graph()
->>> g = graph.traversal().withRemote(DriverRemoteConnection('ws://localhost:8182/gremlin','g'))
-# nested traversal with Python slicing and attribute interception extensions
->>> g.V().hasLabel("person").repeat(both()).times(2).name[0:2].toList()
-[u'marko', u'marko']
->>> g = g.withComputer()
->>> g.V().hasLabel("person").repeat(both()).times(2).name[0:2].toList()
-[u'peter', u'peter']
-# a complex, nested multi-line traversal
->>> g.V().match( \
-...     as_("a").out("created").as_("b"), \
-...     as_("b").in_("created").as_("c"), \
-...     as_("a").out("knows").as_("c")). \
-...   select("c"). \
-...   union(in_("knows"),out("created")). \
-...   name.toList()
-[u'ripple', u'marko', u'lop']
->>>
-----
-
-IMPORTANT: Learn more about Apache TinkerPop's distribution of Gremlin-Python link:https://tinkerpop.apache.org/docs/x.y.z/reference/#gremlin-python[here].
-
-[[gremlin-language-variant-conventions]]
-== Gremlin Language Variant Conventions
-
-Every programming language is different and a Gremlin language variant must ride the fine line between leveraging the
-conventions of the host language and ensuring consistency with Gremlin-Java. A collection of conventions for navigating
-this dual-language bridge are provided.
-
-* If camelCase is not an accepted method naming convention in the host language, then the host language's convention can be used instead. For instance, in a Gremlin-Ruby implementation, `outE("created")` may be `out_e("created")`.
-* If Gremlin-Java step names conflict with the host language's reserved words, then a consistent amelioration should be used. For instance, in Python `as` is a reserved word, thus, Gremlin-Python uses `as_`.
-* If the host language does not use dot-notion for method chaining, then its method chaining convention should be used instead of going the route of operator overloading. For instance, a Gremlin-PHP implementation should do `$g->V()->out()`.
-* If a programming language does not support method overloading, then varargs and type introspection should be used. In Gremlin-Python, `*args` does just that.
-
-== Conclusion
-
-Gremlin is a simple language because it uses two fundamental programming language constructs: *function composition*
-and *function nesting*. Because of this foundation, it is relatively easy to implement Gremlin in any modern programming
-language. Two ways of doing this for the Python language were presented in this tutorial. One using Jython (on the JVM) and one using Python
-(on CPython). It is strongly recommended that language variant designers leverage (especially when not on the JVM)
-the reflection-based source code generation technique presented. This method ensures that the language
-variant is always in sync with the corresponding Apache TinkerPop Gremlin-Java release version. Moreover, it reduces
-the chance of missing methods or creating poorly implemented methods. While Gremlin is simple, there are nearly 200
-step variations in `GraphTraversal`. As such, mechanical means of host language embedding are strongly advised.
+Please see the link:https://tinkerpop.apache.org/docs/x.y.z/reference/#gremlin-drivers-variants[Reference Documentation]
+for more information on Gremlin Language Variants.
\ No newline at end of file
diff --git a/docs/src/tutorials/the-gremlin-console/index.asciidoc b/docs/src/tutorials/the-gremlin-console/index.asciidoc
index c4d08f3..ad04607 100644
--- a/docs/src/tutorials/the-gremlin-console/index.asciidoc
+++ b/docs/src/tutorials/the-gremlin-console/index.asciidoc
@@ -571,9 +571,9 @@
 gremlin> :install com.datastax.cassandra cassandra-driver-core 2.1.9
 ==>Loaded: [com.datastax.cassandra, cassandra-driver-core, 2.1.9]
 gremlin> import com.datastax.driver.core.*
-==>groovy.grape.Grape, org.apache.commons.configuration.*, ..., com.datastax.driver.core.*
+==>groovy.grape.Grape, org.apache.commons.configuration2.*, ..., com.datastax.driver.core.*
 gremlin> import static com.datastax.driver.core.querybuilder.QueryBuilder.*
-==>groovy.grape.Grape, org.apache.commons.configuration.*, ..., static com.datastax.driver.core.querybuilder.QueryBuilder.*
+==>groovy.grape.Grape, org.apache.commons.configuration2.*, ..., static com.datastax.driver.core.querybuilder.QueryBuilder.*
 gremlin> cluster = com.datastax.driver.core.Cluster.builder().addContactPoint("localhost").build()
 ==>com.datastax.driver.core.Cluster@3e1624c7
 gremlin> session = cluster.connect()
diff --git a/docs/src/upgrade/appendix.asciidoc b/docs/src/upgrade/appendix.asciidoc
index a9df0e4..7ce5b22 100644
--- a/docs/src/upgrade/appendix.asciidoc
+++ b/docs/src/upgrade/appendix.asciidoc
@@ -24,8 +24,8 @@
 
 One of the major differences between TinkerPop 2.x and TinkerPop 3.x is that in TinkerPop 3.x, the Java convention of
 using setters and getters was abandoned in favor of a syntax that is more aligned with the syntax of Gremlin-Groovy in
-TinkerPop2. Given that Gremlin-Java8 and Gremlin-Groovy are nearly identical due to the inclusion of Java 8 lambdas, a
-big effort was made to ensure that both languages were as similar as possible.
+TinkerPop2. Given that Gremlin-Java and Gremlin-Groovy are nearly identical due to the inclusion of lambdas from
+Java 8, a big effort was made to ensure that both languages were as similar as possible.
 
 In addition, TinkerPop2 and below made a sharp distinction between the various TinkerPop projects: Blueprints, Pipes,
 Gremlin, Frames, Furnace, and Rexster. With TinkerPop 3.x, all of these projects have been merged and are generally
diff --git a/docs/src/upgrade/index.asciidoc b/docs/src/upgrade/index.asciidoc
index a2bf20f..8e78f4f 100644
--- a/docs/src/upgrade/index.asciidoc
+++ b/docs/src/upgrade/index.asciidoc
@@ -34,6 +34,8 @@
 * Graph Language Provider
 * Graph Plugin Provider
 
+include::release-3.5.x.asciidoc[]
+
 include::release-3.4.x.asciidoc[]
 
 include::release-3.3.x.asciidoc[]
diff --git a/docs/src/upgrade/release-3.5.x.asciidoc b/docs/src/upgrade/release-3.5.x.asciidoc
new file mode 100644
index 0000000..d3e8f1e
--- /dev/null
+++ b/docs/src/upgrade/release-3.5.x.asciidoc
@@ -0,0 +1,1141 @@
+////
+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.
+////
+
+= TinkerPop 3.5.0
+
+image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/images/gremlin-sleeping-beauty.png[width=225]
+
+*The Sleeping Gremlin: No. 18 Entr'acte Symphonique*
+
+== TinkerPop 3.5.0
+
+*Release Date: May 3, 2021*
+
+Please see the link:https://github.com/apache/tinkerpop/blob/3.5.0/CHANGELOG.asciidoc#release-3-5-0[changelog] for a complete list of all the modifications that are part of this release.
+
+=== Upgrading for Users
+
+==== Host Language Runtimes
+
+TinkerPop implements Gremlin in a variety of different programming languages. For 3.5.0, there are a number of major
+upgrades to those programming language environments:
+
+* *Java* - TinkerPop now builds and is compatible with Java 11.
+* *Python* - Support for Python 2.x has been dropped completely. Users must use Python 3 going forward. For the most
+part, from a user’s perspective, there are no specific API changes to consider as a result of this change.
+* *Javascript* - Upgraded to support Node version 10.
+* *Jython* - Support for Jython has been removed and gremlin-python no longer produces a JVM-based artifact. This change
+means that the `GremlinJythonScriptEngine` no longer exists and there is no way to write native Python lambdas that can
+execute in Gremlin Server. All lambdas should be written using gremlin-groovy if they are needed.
+* *.NET* - Gremlin.NET no longer targets .NET Standard 1.3, but only .NET Standard 2.0. Since .NET Core 2.0 and .NET
+Framework 4.6.1 already support this .NET Standard version, most users should not be impacted by this.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2076[TINKERPOP-2076],
+link:https://issues.apache.org/jira/browse/TINKERPOP-2317[TINKERPOP-2317],
+link:https://issues.apache.org/jira/browse/TINKERPOP-2335[TINKERPOP-2335]
+
+==== Gremlint
+
+Gremlint, the JavaScript library powering link:https://www.gremlint.com[gremlint.com], is now part of the TinkerPop
+project. It provides utilities for formatting Gremlin queries, taking parameters such as indentation, maximum line
+length and dot placement into account.
+
+Until recently Gremlint has been an independent project maintained by Øyvind Sæbø, a developer at Ardoq. Ardoq has
+since donated Gremlint, as well as gremlint.com, to TinkerPop so that it can serve as TinkerPop's canonical Gremlin
+code formatter.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2530[TINKERPOP-2530]
+
+==== Translators
+
+`Translator` implementations were moved from a mostly quiet and internal feature of TinkerPop to a documented and more
+readily accessible form in 3.4.9. For 3.5.0, the functionality has been expanded significantly in a number of ways.
+First, for Java, `gremlin-core` now has a `JavascriptTranslator` and a `DotNetTranslator` which completes the set of
+Gremlin translation functions for the programming languages that TinkerPop supports. It is therefore now possible to
+convert Gremlin bytecode to string representations that can compile in C#, Groovy, Javascript and Python.
+
+The following example demonstrates what this functionality looks like in Javascript but it is quite similar for each
+`Translator` implementation:
+
+[source,java]
+----
+// gremlin-core module
+import org.apache.tinkerpop.gremlin.process.traversal.translator.JavascriptTranslator;
+
+GraphTraversalSource g = ...;
+Traversal<Vertex,Integer> t = g.V().has("person","name","marko").
+                                where(in("knows")).
+                                values("age").
+                                map(Lambda.function("it.get() + 1"));
+
+Translator.ScriptTranslator javascriptTranslator = JavascriptTranslator.of("g");
+System.out.println(javascriptTranslator.translate(t).getScript());
+// OUTPUT: g.V().has("person","name","marko").where(__.in_("knows")).values("age").map(() => "it.get() + 1")
+----
+
+In addition, a native Python `Translator` implementation has been added that will generate a string of Gremlin that
+will compile on the JVM.
+
+[source,python]
+----
+from gremlin_python.process.translator import *
+
+g = ...
+t = (g.V().has('person','name','marko').
+          where(__.in_("knows")).
+          values("age"))
+
+# Groovy
+translator = Translator().of('g');
+print(translator.translate(t.bytecode));
+# OUTPUT: g.V().has('person','name','marko').where(__.in('knows')).values('age')
+----
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2451[TINKERPOP-2451],
+link:https://issues.apache.org/jira/browse/TINKERPOP-2452[TINKERPOP-2452],
+link:https://issues.apache.org/jira/browse/TINKERPOP-2527[TINKERPOP-2527]
+
+==== Versions and Dependencies
+
+*Apache Commons*
+
+There is a major breaking change in the use of `Configuration` objects. Prior to 3.5.0, `Configuration` objects were
+from the Apache Commons `commons-configuration` library, but in this version, they are of `commons-configuration2`.
+While this is a breaking change, the fix for most implementations will be quite simple and amounts to changing the
+import statements from:
+
+[source,text]
+----
+org.apache.commons.configuration.*
+----
+
+to
+
+[source,text]
+----
+org.apache.commons.configuration2.*
+----
+
+It is also worth noting that default list handling in configurations is treated differently. TinkerPop largely
+disabled the default list handling approach in `Configuration` 1.x, but if that functionality is still needed, it can
+be reclaimed by setting the `LegacyListDelimiterHandler` - details for doing taking this step and other relevant
+upgrade information can be found in the link:https://commons.apache.org/proper/commons-configuration/userguide/upgradeto2_0.html[2.x Upgrade Documentation].
+
+*Neo4j*
+
+There were two key changes to the `neo4j-gremlin` module:
+
+* The underlying Neo4j version moved from the 3.2.x line to 3.4.x line. Please see the
+link:https://neo4j.com/guides/upgrade-archive/[Neo4j Upgrade FAQ] for more information as features and
+configuration options may have changed.
+* Experimental support for multi/meta-properties in Neo4j which were previously deprecated have now been permanently
+removed.
+
+*Groovy Dependency in Java Driver*
+
+The `gremlin-driver` module made its dependency on Groovy `optional` as its only reason for inclusion was to support
+`JsonBuilder` serialization and this feature is little known and perhaps even less used. Read more about this change
+here in the Upgrade Documentation in the <<serialization-3_5_0, Serialization Section>> under the subsection title
+"GraphSON and JsonBuilder".
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2185[TINKERPOP-2185]
+
+==== Shaded Java Driver
+
+The `gremlin-driver` has an additional packaging which may make it easier to upgrade for some users who may have
+extensive dependency chains.
+
+[source,xml]
+----
+<dependency>
+   <groupId>org.apache.tinkerpop</groupId>
+   <artifactId>gremlin-driver</artifactId>
+   <version>x.y.z</version>
+   <classifier>shaded</classifier>
+</dependency>
+----
+
+The above dependency with the `shaded` classifier shades all the non-optional dependencies of `gremlin-driver` and
+includes `gremlin-core` and `tinkergraph-gremlin` in an unshaded form. The slf4j dependency was not included because
+shading it can cause problems with its operations.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2476[TINKERPOP-2476]
+
+[[serialization-3_5_0]]
+==== Serialization
+
+*Java and Gryo*
+
+Since the first release of TinkerPop 3.x, Gryo has been the default serialization format for Gremlin Server and
+Java Driver. It was also used as the default serialization format for Gremlin Console remote connectivity to Gremlin
+Server. As of this release, Gryo has been replaced as the default by GraphBinary. All packaged configuration files
+and programmatic defaults have been modified as such.
+
+It is still possible to utilize Gryo as a message serialization format by modifying Gremlin Server configuration files
+to include the appropriate Gryo configurations. If using Gryo, do not use earlier versions of the driver and server
+with 3.5.0. Use a 3.5.0 client to connect to a 3.5.0 server. Generally speaking, mixed version combinations will
+appear to work properly, but problems will likely occur during general course of usage and it is therefore not
+advisable to take this approach.
+
+For best compatibility between 3.4.x and 3.5.x, please use GraphBinary.
+
+*GraphSON and JsonBuilder*
+
+GraphSON serialization support for Groovy's `JsonBuilder` has been present since the first version of GraphSON. That
+approach to returning results has never materialized as a standardized way to use Gremlin as originally envisioned.
+While support for this serialization form is still present, the dependency on Groovy in `gremlin-driver` has been
+changed to "optional", which means that users who wish to continue to return `JsonBuilder` results for some
+reason must explicitly include `groovy` and `groovy-json` dependencies in their applications. For Maven this would
+mean adding the following dependencies:
+
+[source,xml]
+----
+<dependency>
+    <groupId>org.codehaus.groovy</groupId>
+    <artifactId>groovy</artifactId>
+    <version>${groovy.version}</version>
+    <classifier>indy</classifier>
+</dependency>
+<dependency>
+    <groupId>org.codehaus.groovy</groupId>
+    <artifactId>groovy-json</artifactId>
+    <version>${groovy.version}</version>
+    <classifier>indy</classifier>
+    <exclusions>
+        <!-- exclude non-indy type -->
+        <exclusion>
+            <groupId>org.codehaus.groovy</groupId>
+            <artifactId>groovy</artifactId>
+        </exclusion>
+    </exclusions>
+</dependency>
+----
+
+The `${groovy.version}` should match the version specified in TinkerPop's root
+link:https://github.com/apache/tinkerpop/blob/master/pom.xml[pom.xml].
+
+*.NET: GraphBinary*
+
+Gremlin.NET now also supports GraphBinary. GraphSON 3 however still remains the default serialization format as
+GraphBinary should be considered experimental for this version in .NET:
+
+[source,csharp]
+----
+include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Upgrade/Release35Tests.cs[tags=graphBinary]
+----
+
+*.NET: New JSON Library*
+
+Gremlin.NET now uses `System.Text.Json` instead of Newtonsoft.Json as `System.Text.Json` is already included in .NET
+Core 3.0 and higher which removes a dependency and offers better performance. Most users should not notice this change,
+however users who have implemented their own GraphSON serializers or deserializers will need to modify them
+accordingly. The same applies to users that let Gremlin.NET return data without deserializing it first as the returned
+data types will change in this case, for example from Newtonsoft.Json's `JObject` or `JToken` to `JsonElement` with
+`System.Text.Json`.
+
+*Python dict Deserialization*
+
+In Gremlin it is common to return a `dict` or `list` as a key value in another `dict`. The problem for Python is that
+these values are not hashable and will result in an error. By introducing a `HashableDict` and `Tuple` for those keys
+(respectively), it is now possible to return these types of results and not have to work around them:
+
+[source,text]
+----
+>>> g.V().has('person', 'name', 'marko').elementMap("name").groupCount().next()
+{{<T.id: 1>: 1, <T.label: 4>: 'person', 'name': 'marko'}: 1}
+----
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2259[TINKERPOP-2259],
+link:https://issues.apache.org/jira/browse/TINKERPOP-2349[TINKERPOP-2349],
+link:https://issues.apache.org/jira/browse/TINKERPOP-2395[TINKERPOP-2395],
+link:https://issues.apache.org/jira/browse/TINKERPOP-2407[TINKERPOP-2407],
+link:https://issues.apache.org/jira/browse/TINKERPOP-2460[TINKERPOP-2460],
+link:https://issues.apache.org/jira/browse/TINKERPOP-2472[TINKERPOP-2472],
+link:http://tinkerpop.apache.org/docs/3.5.0/dev/provider/#_supporting_gremlin_net_io[Custom JSON serialization with Gremlin.NET]
+
+==== Transaction Improvements
+
+The TinkerPop Transaction API and its related features have not changed much since TinkerPop 3.x was initially
+released. Transactions that extend beyond the scope of a single traversal (or request) have remained a feature for
+embedded use cases and script execution (where supported) even in the face of the rise of remote graph use cases.
+With the varying contexts that exist for how and when transactions can be used, it has led to a fair bit of confusion.
+
+For 3.5.0, TinkerPop introduces a change in approach to transactions that has the goal of unifying the API and features
+for all use cases, while addressing the more current state of the graph ecosystem which has shifted heavily toward
+remote communication and more diverse programming language ecosystems beyond the JVM.
+
+NOTE: The old transaction API remains intact in 3.5.0, so this version should be backward compatible with the old
+model for embedded transactions.
+
+The new model for using a transaction looks like this:
+
+[source,groovy]
+----
+g = traversal().withEmbedded(graph)
+// or
+g = traversal().withRemote(conn)
+
+tx = g.tx() // create a Transaction object
+gtx = tx.begin()  // spawn a GraphTraversalSource from the Transaction
+assert tx.isOpen() == true
+gtx.addV('person').iterate()
+gtx.addV('software').iterate()
+tx.commit() // alternatively you could explicitly rollback()
+assert tx.isOpen() == false
+
+// it is still possible to use g, but gtx is "done" after it is closed so use
+// tx.begin() to produce a new gtx instance for a fresh transaction
+assert 2 == g.V().count().next()
+----
+
+The first important point to take away here is that the same transaction code will work for either embedded or remote
+use cases. The second important point is that for remote cases, transaction support with bytecode is a wholly new
+feature, which was implemented by providing support for bytecode in sessions. Up until this time, sessions could only
+support script-based requests, so that makes another added feature related to this one.
+
+IMPORTANT: The `g.tx()` is only supported in Java at this time. Support for other languages will come available in
+future releases on the 3.5.x line.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2537[TINKERPOP-2537],
+link:https://tinkerpop.apache.org/docs/current/reference/#transactions[Reference Documentation - Transactions]
+
+==== Anonymous Child Traversals
+
+TinkerPop conventions for child traversals is to spawn them anonymously from `__`, therefore:
+
+[source,groovy]
+g.addV('person').addE('self').to(__.V(1))
+
+or more succinctly via static import as:
+
+[source,groovy]
+g.addV('person').addE('self').to(V(1))
+
+Some users have chosen to instead write the above as:
+
+[source,groovy]
+g.addV('person').addE('self').to(g.V(1))
+
+which spawns a child traversal from a `GraphTraversalSource`. When spawned this way, a traversal is bound to a "source"
+and therefore is not anonymous. While the above code worked, it is important that there be less ways to do things
+with Gremlin so as to avoid confusion in examples, documentations and mailing list answers.
+
+As of 3.5.0, attempting to use a traversal spawned from a "source" will result in an exception. Users will need to
+modify their code if they use the unconventional syntax.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2361[TINKERPOP-2361]
+
+==== Use of null
+
+Gremlin has traditionally disallowed `null` as a value in traversals and not always in consistent ways:
+
+[source,text]
+----
+gremlin> g.inject(1, null, null, 2, null)
+java.lang.NullPointerException
+Type ':help' or ':h' for help.
+Display stack trace? [yN]n
+gremlin> g.V().has('person','name','marko').property('age', null)
+The AddPropertyStep does not have a provided value: AddPropertyStep({key=[age]})
+Type ':help' or ':h' for help.
+Display stack trace? [yN]
+gremlin> g.addV("person").property("name", 'stephen').property("age", null)
+==>v[13]
+gremlin> g.V().has('person','name','stephen').elementMap()
+==>[id:13,label:person,name:stephen]
+gremlin> g.V().constant(null)
+gremlin>
+----
+
+Note how `null` can produce exception behavior or act as a filter. For 3.5.0, TinkerPop has not only made `null` usage
+consistent, but has also made it an allowable value within a `Traversal`:
+
+[source,text]
+----
+gremlin> g.inject(1, null, null, 2, null)
+==>1
+==>null
+==>null
+==>null
+==>2
+gremlin> g.V().constant(null)
+==>null
+==>null
+==>null
+==>null
+==>null
+==>null
+----
+
+TinkerGraph can be configured to support `null` as a property value and all graphs may not support this feature (for
+example, Neo4j does not). Please be sure to check the new `supportsNullPropertyValues()` feature (or the documentation
+of the graph provider) to determine if the `Graph` implementation allows `null` as a property value.
+
+With respect to `null` in relation to properties, there was a bit of inconsistency in the handling of `null` in calls
+to `property()` depending on the type of mutation being executed demonstrated as follows in earlier versions:
+
+[source,text]
+----
+gremlin> g.V(1).property("x", 1).property("y", null).property("z", 2)
+The AddPropertyStep does not have a provided value: AddPropertyStep({key=[y]})
+Type ':help' or ':h' for help.
+Display stack trace? [yN]N
+gremlin> g.addV("test").property("x", 1).property("y", null).property("z", 2)
+==>v[13]
+gremlin> g.V(13).properties()
+==>vp[x->1]
+==>vp[z->2]
+----
+
+This behavior has been altered to become consistent. First, assuming `null` is not supported as a property value, the
+setting of a property to `null` should have the behavior of removing the property in the same way in which you might
+do `g.V().properties().drop()`:
+
+[source,text]
+----
+gremlin> g.V(1).property("x", 1).property("y", null).property("z", 2)
+==>v[1]
+gremlin> g.V(1).elementMap()
+==>[id:1,label:person,name:marko,x:1,z:2,age:29]
+gremlin> g.V().hasLabel('person').property('age',null).iterate()
+gremlin> g.V().hasLabel('person').elementMap()
+==>[id:1,label:person,name:marko]
+==>[id:2,label:person,name:vadas]
+==>[id:4,label:person,name:josh]
+==>[id:6,label:person,name:peter]
+----
+
+Then, assuming `null` is supported as a property value, it would simply store the `null` for the key:
+
+[source,text]
+----
+gremlin> g.addV("person").property("name", 'stephen').property("age", null)
+==>v[13]
+gremlin> g.V().has('person','name','stephen').elementMap()
+==>[id:13,label:person,name:stephen,age:null]
+gremlin> g.V().has('person','age',null)
+==>v[13]
+----
+
+The above described changes also have an effect on steps like `group()` and `groupCount()` which formerly produced
+exceptions when keys could not be found:
+
+[source,text]
+----
+gremlin> g.V().group().by('age')
+The property does not exist as the key has no associated value for the provided element: v[3]:age
+Type ':help' or ':h' for help.
+Display stack trace? [yN]n
+----
+
+For situations where the key did not exist, the approach was to filter away vertices that did not have the available
+key so that such steps would work properly or to write a more complex `by()` modulator to better handle the possibility
+of a missing key. With the latest changes however none of that is necessary unless desired:
+
+[source,text]
+----
+gremlin> g.V().groupCount().by('age')
+==>[null:2,32:1,35:1,27:1,29:1]
+----
+
+In conclusion, this improved support of `null` may affect the behavior of existing traversals written in past
+versions of TinkerPop as it is no longer possible to rely on `null` to expect a filtering action for traversers.
+Please review existing Gremlin carefully to ensure that there are no unintended consequences of this change and that
+there are no opportunities to improve existing logic to take greater advantage of this expansion of `null` semantics.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2235[TINKERPOP-2235],
+link:https://issues.apache.org/jira/browse/TINKERPOP-2099[TINKERPOP-2099]
+
+==== ByModulatorOptimizationStrategy
+
+The new `ByModulatorOptimizationStrategy` attempts to re-write `by()` modulator traversals to use their more optimized
+forms which can provide a major performance improvement. As a simple an example, a traversal like `by(id())` would
+be replaced by `by(id)`, thus replacing a step-based traversal with a token-based traversal.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-1682[TINKERPOP-1682]
+
+==== SeedStrategy
+
+The new `SeedStrategy` allows the user to set a seed value for steps that make use of `Random` so that the traversal
+has the ability to return deterministic results. While this feature is useful for testing and debugging purposes,
+there are also some practical applications as well.
+
+[source,text]
+----
+gremlin> g.V().values('name').fold().order(local).by(shuffle)
+==>[josh,marko,vadas,peter,ripple,lop]
+gremlin> g.V().values('name').fold().order(local).by(shuffle)
+==>[vadas,lop,marko,peter,josh,ripple]
+gremlin> g.V().values('name').fold().order(local).by(shuffle)
+==>[peter,ripple,josh,lop,marko,vadas]
+gremlin> g.withStrategies(new SeedStrategy(22323)).V().values('name').fold().order(local).by(shuffle)
+==>[lop,peter,josh,marko,vadas,ripple]
+gremlin> g.withStrategies(new SeedStrategy(22323)).V().values('name').fold().order(local).by(shuffle)
+==>[lop,peter,josh,marko,vadas,ripple]
+gremlin> g.withStrategies(new SeedStrategy(22323)).V().values('name').fold().order(local).by(shuffle)
+==>[lop,peter,josh,marko,vadas,ripple]
+----
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2014[TINKERPOP-2014]
+
+==== by(T) for Property
+
+The `Property` interface is not included in the hierarchy of `Element`. This means that an edge property or a
+meta-property are not considered elements the way that a `VertexProperty` is. As a result, some usages of `T` in
+relation to properties do not work consistently. One such example is `by(T)`, a token-based traversal, where the
+following works for a `VertexProperty` but will not for edge properties or meta-properties:
+
+[source,text]
+----
+gremlin> g.V(1).properties().as('a').select('a').by(key)
+==>name
+==>age
+----
+
+For a `Property` you would need to use `key()`-step:
+
+[source,text]
+----
+gremlin> g.E(11).properties().as('a').select(last,'a').by(key())
+==>weight
+----
+
+Aside from the inconsistency, this issue also presents a situation where performance is impacted as token-based
+traversals are inherently faster than step-based ones. In 3.5.0, this issue has been resolved in conjunction with the
+introduction of `ByModulatorOptimizationStrategy` which will optimize `by(key())` and `by(value())` to their
+appropriate token versions automatically.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-1682[TINKERPOP-1682]
+
+==== match() Consistency
+
+The `match()` step behavior might have seemed inconsistent those first using it. While there are a number of examples
+that might demonstrate this issue, the easiest one to consume would be:
+
+[source,text]
+----
+gremlin> g.V().match(__.as("a").out("knows").as("b"))
+==>[a:v[1],b:v[2]]
+==>[a:v[1],b:v[4]]
+gremlin> g.V().match(__.as("a").out("knows").as("b")).unfold()
+gremlin> g.V().match(__.as("a").out("knows").as("b")).identity()
+==>[]
+==>[]
+----
+
+The output is unexpected if there isn't awareness of some underlying optimizations at play, where `match()` as the
+final step in the traversal implies that the user wants all of the labels as part of the output. With the addition
+of the extra steps, `unfold()` and `identity()` in the above case, the implication is that the traversal must be
+explicit in the labels to preserve from match, thus:
+
+[source,text]
+----
+gremlin> g.V().match(__.as("a").out("knows").as("b")).select('a','b').unfold()
+==>a=v[1]
+==>b=v[2]
+==>a=v[1]
+==>b=v[4]
+gremlin> g.V().match(__.as("a").out("knows").as("b")).select('a','b').identity()
+==>[a:v[1],b:v[2]]
+==>[a:v[1],b:v[4]]
+----
+
+Being explicit, as is the preference in writing Gremlin to good form, helps restrict the path history required to
+execute the traversal and therefore preserves memory. Of course, making `match()` a special form of end step is a
+confusing approach as the behavior of the step changes simply because another step is in play. Furthermore, correct
+execution of the traversal, relies on the execution of traversal strategies when the same traversal should produce
+the same results irrespective of the strategies applied to it.
+
+In 3.5.0, we look to better adhere to that guiding design principle and ensure a more consistent output for these types
+of traversals. While the preferred method is to specify the labels to preserve from `match()` with a following
+`select()` step as shown above, `match()` will now consistently return all labels when they are not specified
+explicitly.
+
+[source,text]
+----
+gremlin> g.V().match(__.as("a").out("knows").as("b"))
+==>[a:v[1],b:v[2]]
+==>[a:v[1],b:v[4]]
+gremlin> g.V().match(__.as("a").out("knows").as("b")).identity()
+==>[a:v[1],b:v[2]]
+==>[a:v[1],b:v[4]]
+gremlin> g.V().match(__.as("a").out("knows").as("b")).unfold()
+==>a=v[1]
+==>b=v[2]
+==>a=v[1]
+==>b=v[4]
+----
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2481[TINKERPOP-2481],
+link:https://issues.apache.org/jira/browse/TINKERPOP-2499[TINKERPOP-2499]
+
+==== Gremlin Server
+
+*Remote SideEffects*
+
+Remote traversals no longer support the retrieval of remote side-effects. Users must therefore directly return
+side-effects as part of their query if they need that data. Note that server settings for `TraversalOpProcessor`, which
+formerly held the cache for these side-effects, no longer have any effect and can be removed.
+
+*Audit Logging*
+
+The `authentication.enableAuditlog` configuration property is deprecated and replaced by the `enableAuditLog` property
+to also make it available to `Authorizer` implementations. With the new setting enabled, there are slight changes in the
+formatting of audit log messages. In particular, the name of the authenticated user is included in every message.
+
+*Authorization*
+
+While Gremlin Server has long had authentication options to determine if a user can connect to the server, it now also
+contains the ability to apply a level of authorization to better control what a particular authenticated user will
+have access to. Authorization is controlled by the new `Authorizer` interface, which can be implemented by users and
+graph providers to provide this custom functionality.
+
+*UnifiedChannelizer*
+
+Gremlin Server uses a `Channelizer` abstraction to configure different Netty pipelines which can then offer different
+server behaviors. Most commonly, users configure the `WebSocketChannelizer` to enable the websocket protocol to which
+the various language drivers can connect.
+
+TinkerPop 3.5.0 introduces a new `Channelizer` implementation called the `UnifiedChannelizer`. This channelizer is
+somewhat similar to the `WsAndHttpChannelizer` in that combines websocket and standard HTTP protocols in the server,
+but it provides a new and improved thread management approach as well as a more streamlined execution model. The
+`UnifiedChannelizer` technically replaces all existing implementations, but is not yet configured by default in Gremlin
+Server. To use it, modify the `channelizer` setting in the server yaml file as follows:
+
+[source,yaml]
+----
+channelizer: org.apache.tinkerpop.gremlin.server.channel.UnifiedChannelizer
+----
+
+As the `UnifiedChannelizer` is tested further, it will eventually become the default implementation. It may however
+be the preferred channelizer when using large numbers of short-lived sessions as the the threading model of the
+`UnifiedChannelizer` is better suited for such situations. If using this new channelizer, there are a few considerations
+to keep in mind:
+
+* The `UnifiedChannelizer` does not use the `OpProcessor` infrastructure, therefore those
+link:https://tinkerpop.apache.org/docs/3.5.0/reference/#opprocessor-configurations[configurations] are no longer
+relevant and can be ignored.
+* It is important to read about the `gremlinPool` setting in the link:https://tinkerpop.apache.org/docs/3.5.0/reference/#_tuning[Tuning Section] of
+the reference documentation and to look into the link:https://tinkerpop.apache.org/docs/3.5.0/reference/#_configuring_2[new configurations]
+available related to this channelizer: `maxParameters`, `sessionLifeTimeout`, `useGlobalFunctionCacheForSessions`, and
+`useCommonEngineForSessions`.
+* Generally speaking, if current usage patterns involve mixing heavy loads of sessionless requests with arbitrary
+numbers of long-run sessions that have unpredictable end times, then the `UnifiedChannelizer` may not be the right
+choice for that situation. The long-run sessions will consume threads that would normally be available to sessionless
+requests and eventually slow their processing. On the other hand, if usage patterns involve mixing heavy loads of
+sessionless requests with short-lived sessions of similar execution time or if usage patterns allow the ability to
+predict the size of the pool that will support the workload then the `UnifiedChannelizer` will greatly improve
+performance over the old model.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2245[TINKERPOP-2245],
+link:https://issues.apache.org/jira/browse/TINKERPOP-2269[TINKERPOP-2269],
+link:https://issues.apache.org/jira/browse/TINKERPOP-2389[TINKERPOP-2389],
+link:https://tinkerpop.apache.org/docs/3.5.0/reference/#authorization[Reference Documentation]
+
+==== Retry Conditions
+
+Some error conditions are temporary in nature and therefore an operation that ends in such a situation may be tried
+again as-is to potential success. In embedded use cases, an exception that implements the `TemporaryException`
+interface implies that the failing operation can be retried. For remote use cases, a `ResponseStatusCode` of `596`
+which equates to `SERVER_ERROR_TEMPORARY` is an indicator that a request may be retried.
+
+With this more concrete and generalized approach to determining when retries should happen, the need to trap provider
+specific exceptions or to examine the text of error messages are removed. Before replacing existing code that might
+do these things currently, it may be best to include this sort of retry checking in addition to current methods as
+it may take time for providers to support these new options. Alternatively, if you can confirm that a provider does
+support this functionality then feel free to proceed wholly with this generalized TinkerPop approach.
+
+Finally, it is important to note that TinkerPop drivers do not automatically retry when these conditions are met. It
+is up to the application to determine if retry is desired and how best to do so.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2517[TINKERPOP-2517]
+
+==== Python Transport Layer
+
+With the removal of Python 2.x support the transport layer of gremlin-python has been rewritten to use a library that
+utilizes the asyncio event loop of Python 3. link:https://github.com/aio-libs/aiohttp[AIOHTTP] utilizes Python 3's
+event loop with a minimal HTTP abstraction and is now used for the transport layer. From a user's perspective there is
+not much of a change except there is now new configuration options available through named parameters, see
+link:https://docs.aiohttp.org/en/stable/client_reference.html#aiohttp.ClientSession.ws_connect[AIOHTTP ws_connect] for
+more details. This change fixed a number of issues that were related to the IOLoop of the old
+link:https://github.com/tornadoweb/tornado[Tornado] transport layer, which has been completely removed from the
+library. An additional config which enables the driver to be used from within an event loop has been added and can be
+used by setting `call_from_event_loop=True` when connecting.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-1886[TINKERPOP-1886],
+link:https://issues.apache.org/jira/browse/TINKERPOP-2388[TINKERPOP-2388],
+link:https://issues.apache.org/jira/browse/TINKERPOP-2484[TINKERPOP-2484],
+link:https://issues.apache.org/jira/browse/TINKERPOP-2546[TINKERPOP-2546],
+
+==== Python Kerberos Support
+
+The Python Driver now supports Kerberos based authentication:
+
+[source,python]
+----
+g = traversal().withRemote(DriverRemoteConnection(
+    'ws://localhost:8182/gremlin', 'g', kerberized_service='gremlin@hostname.your.org'))
+----
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-1641[TINKERPOP-1641],
+link:https://tinkerpop.apache.org/docs/current/reference/#gremlin-python-connecting[Reference Documentation]
+
+==== Deprecation Removal
+
+The following deprecated classes, methods or fields have been removed in this version:
+
+* `gremlin-core`
+** `org.apache.tinkerpop.gremlin.process.computer.bulkdumping.BulkDumperVertexProgram`
+** `org.apache.tinkerpop.gremlin.process.computer.bulkloading.BulkLoader`
+** `org.apache.tinkerpop.gremlin.process.computer.bulkloading.BulkLoaderVertexProgram`
+** `org.apache.tinkerpop.gremlin.process.computer.bulkloading.IncrementalBulkLoader`
+** `org.apache.tinkerpop.gremlin.process.computer.bulkloading.OneTimeBulkLoader`
+** `org.apache.tinkerpop.gremlin.process.computer.clustering.peerpressure.PeerPressureVertexProgram.Builder#traversal(*)`
+** `org.apache.tinkerpop.gremlin.process.computer.ranking.pagerank.PageRankVertexProgram.Builder#traversal(*)`
+** `org.apache.tinkerpop.gremlin.process.computer.ranking.pagerank.PageRankVertexProgram.Builder#vertexCount()`
+** `org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.PageRankVertexProgramStep.modulateBy(*)`
+** `org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.PageRankVertexProgramStep.modulateTimes()`
+** `org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.PeerPressureVertexProgramStep.modulateBy(*)`
+** `org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.PeerPressureVertexProgramStep.modulateTimes()`
+** `org.apache.tinkerpop.gremlin.process.remote.traversal.AbstractRemoteTraversalSideEffects`
+** `org.apache.tinkerpop.gremlin.process.remote.traversal.EmbeddedRemoteTraversalSideEffects`
+** `org.apache.tinkerpop.gremlin.process.remote.traversal.RemoteTraversalSideEffects`
+** `org.apache.tinkerpop.gremlin.process.remote.traversal.RemoteTraversal#getSideEffects()`
+** `org.apache.tinkerpop.gremlin.process.traversal.Order.decr`
+** `org.apache.tinkerpop.gremlin.process.traversal.Order.incr`
+** `org.apache.tinkerpop.gremlin.process.traversal.TraversalSource#withRemote(*)`
+** `org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource#withRemote(*)`
+** `org.apache.tinkerpop.gremlin.process.traversal.step.map.PropertyMapStep(Traversal.Admin, boolean, PropertyType, String...)`
+** `org.apache.tinkerpop.gremlin.process.traversal.step.map.PropertyMapStep#isIncludeTokens()`
+** `org.apache.tinkerpop.gremlin.process.traversal.util.BytecodeUtil`
+** `org.apache.tinkerpop.gremlin.structure.util.star.StarGraph#builder()`
+** `org.apache.tinkerpop.gremlin.structure.util.star.StarGraph.Builder#create()`
+* `gremlin-driver`
+** `org.apache.tinkerpop.gremlin.driver.Tokens#ARGS_SCRIPT_EVAL_TIMEOUT`
+** `org.apache.tinkerpop.gremlin.driver.Channelizer#createKeepAliveMessage()`
+** `org.apache.tinkerpop.gremlin.driver.Channelizer#supportsKeepAlive()`
+** `org.apache.tinkerpop.gremlin.driver.Cluster.Builder#keyCertChainFile(String)`
+** `org.apache.tinkerpop.gremlin.driver.Cluster.Builder#keyFile(String)`
+** `org.apache.tinkerpop.gremlin.driver.Cluster.Builder#keyPassword(String)`
+** `org.apache.tinkerpop.gremlin.driver.Cluster.Builder#maxWaitForSessionClose(Integer)`
+** `org.apache.tinkerpop.gremlin.driver.Cluster.Builder#trustCertificateChainFile(String)`
+** `org.apache.tinkerpop.gremlin.driver.handler.NioGremlinRequestEncoder`
+** `org.apache.tinkerpop.gremlin.driver.handler.NioGremlinResponseDecoder`
+** `org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteTraversalSideEffects`
+** `org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteTraversal#getSideEffects()`
+** `org.apache.tinkerpop.gremlin.driver.simple.NioClient`
+* `gremlin-python`
+** `org.apache.tinkerpop.gremlin.python.jsr223.*`
+* `gremlin-server`
+** `org.apache.tinkerpop.gremlin.server.Settings.scriptEvaluationTimeout`
+** `org.apache.tinkerpop.gremlin.server.Settings.SslSettings.keyCertChainFile`
+** `org.apache.tinkerpop.gremlin.server.Settings.SslSettings.keyFile`
+** `org.apache.tinkerpop.gremlin.server.Settings.SslSettings.keyPassword`
+** `org.apache.tinkerpop.gremlin.server.Settings.SslSettings.trustCertificateChainFile`
+** `org.apache.tinkerpop.gremlin.server.ResponseHandlerContext`
+** `org.apache.tinkerpop.gremlin.server.channel.NioChannelizer`
+** `org.apache.tinkerpop.gremlin.server.handler.NioGremlinBinaryRequestDecoder`
+** `org.apache.tinkerpop.gremlin.server.handler.NioGremlinResponseFrameEncoder`
+** `org.apache.tinkerpop.gremlin.server.op.AbstractEvalOpProcessor.evalOpInternal(ResponseHandlerContext, Supplier, BindingSupplier)`
+** `org.apache.tinkerpop.gremlin.server.op.AbstractOpProcessor.generateMetaData(ChannelHandlerContext, RequestMessage, ResponseStatusCode, Iterator)`
+** `org.apache.tinkerpop.gremlin.server.op.AbstractOpProcessor.handleIterator(ResponseHandlerContext, Iterator)`
+** `org.apache.tinkerpop.gremlin.server.op.AbstractOpProcessor.makeFrame(ChannelHandlerContext, RequestMessage, MessageSerializer, boolean, List, ResponseStatusCode, Map)`
+** `org.apache.tinkerpop.gremlin.server.op.AbstractOpProcessor.makeFrame(Context, RequestMessage, MessageSerializer, boolean, List, ResponseStatusCode, Map)`
+** `org.apache.tinkerpop.gremlin.server.op.AbstractOpProcessor.makeFrame(ResponseHandlerContext, RequestMessage, MessageSerializer, boolean, List, ResponseStatusCode, Map)`
+** `org.apache.tinkerpop.gremlin.server.op.AbstractOpProcessor.makeFrame(ResponseHandlerContext, RequestMessage, MessageSerializer, boolean, List, ResponseStatusCode, Map, Map)`
+** `org.apache.tinkerpop.gremlin.server.op.traversal.TraversalOpProcessor.onSideEffectSuccess(Graph, Context)`
+** `org.apache.tinkerpop.gremlin.server.util.SideEffectIterator`
+* `neo4j-gremlin`
+** `org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph#getTrait()`
+** `org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph#CONFIG_META_PROPERTIES`
+** `org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph#CONFIG_MULTI_PROPERTIES`
+** `org.apache.tinkerpop.gremlin.neo4j.structure.trait.MultiMetaNeo4jTrait`
+** `org.apache.tinkerpop.gremlin.neo4j.structure.trait.NoMultiNoMetaNeo4jTrait`
+** `org.apache.tinkerpop.gremlin.neo4j.structure.trait.Neo4jTrait`
+
+Certain elements of the API were not or could not be deprecated in prior versions and were simply renamed for this
+release:
+
+* `org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode#SERVER_ERROR_SCRIPT_EVALUATION` became `SERVER_ERROR_EVALUATION`
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2080[TINKERPOP-2080],
+link:https://issues.apache.org/jira/browse/TINKERPOP-2231[TINKERPOP-2231],
+link:https://issues.apache.org/jira/browse/TINKERPOP-2233[TINKERPOP-2233],
+link:https://issues.apache.org/jira/browse/TINKERPOP-2239[TINKERPOP-2239],
+link:https://issues.apache.org/jira/browse/TINKERPOP-2269[TINKERPOP-2269],
+link:https://issues.apache.org/jira/browse/TINKERPOP-2273[TINKERPOP-2273],
+link:https://issues.apache.org/jira/browse/TINKERPOP-2455[TINKERPOP-2455],
+link:https://tinkerpop.apache.org/docs/3.5.0/upgrade/#_ssl_security[3.2.10 Upgrade Documentation for SSL]
+
+=== Upgrading for Providers
+
+==== Graph System Providers
+
+===== Server Authorization
+
+Gremlin Server now supports an extension model that enables authorization. Graph providers are not required to
+implement this functionality in any way, but it can be helpful for those graphs that wish to provide this functionality
+through Gremlin Server. Graphs Systems may still choose to rely on their own native authorization functionality if
+they so choose.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2389[TINKERPOP-2389],
+link:https://tinkerpop.apache.org/docs/3.5.0/reference/#authorization[Reference Documentation],
+link:https://tinkerpop.apache.org/docs/3.5.0/dev/provider/#_authentication_and_authorization[Provider Documentation]
+
+===== ScalarMapStep
+
+Previous versions of `MapStep` had a single abstract method that needed to be implemented:
+
+[source,java]
+----
+protected abstract E map(final Traverser.Admin<S> traverser);
+----
+
+This method made it easy to implement new implementations because it hid certain processing logic and made it so that
+the implementer only had to reason about how to take the current object from the `Traverser` and transform it to a
+new value. As 3.5.0 changed semantics around how `null` is processed, this method became a bit of a hindrance to the
+more complex logic which those semantics entailed. Specifically, this method could not easily communicate to underlying
+processing what a `null` might mean - is the `null` the end of the traversal stream or should the `null` be promoted
+down the stream as a value to be processed.
+
+Interestingly, the method that enabled the handling of this more complex decision making already existed in
+`AbstractStep`:
+
+[source,java]
+----
+protected Traverser.Admin<E> processNextStart()
+----
+
+It returns a whole `Traverser` object and forces manual retrieval of the "next" `Traverser`. At this level it becomes
+possible to make choices on `null` and return it if it should be propagated or dismiss it and return an
+`EmptyTraverser`. To better accommodate the `MapStep` which provides the nice helper `map(Traverser)` method as well
+as the more flexible version that doesn't need that infrastructure, `ScalarMapStep` was added to extend `MapStep`. The
+`map(Traverser)` was then moved to `ScalarMapStep` and those steps that could rely on that helper method now extend
+from it. All other steps of this sort still extend `MapStep` and directly implement `processNextStart()`.
+
+Providers will get compile errors if they extended `MapStep`. The easy solution will be to simply modify that code so
+that their step instead extends `ScalarMapStep`. As a secondary task, providers should then examine their step
+implementation to ensure that `null` semantics as presented in 3.5.0 apply properly. If they do not, then it is likely
+that the step should simply implement `MapStep` directly and former `map(Traverser)` logic should be migrated to
+`processNextStart()`.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2235[TINKERPOP-2235],
+link:https://issues.apache.org/jira/browse/TINKERPOP-2099[TINKERPOP-2099]
+
+===== TraversalStrategy Application
+
+The methodology for strategy application has been altered and the change is most easily described by example. Given a
+traversal with the structure:
+
+[source,text]
+----
+a(b(),c(d()))
+----
+
+Strategies were formerly applied in the following order:
+
+[source,text]
+----
+StrategyA on a
+StrategyB on a
+StrategyA on b
+StrategyB on b
+StrategyA on c
+StrategyB on c
+StrategyA on d
+StrategyB on d
+----
+
+This approach has always prevented strategies from performing global operations across the traversal and all decedents
+effectively as children will not have been processed by preceding strategies yet. As of this release, the approach
+has been altered to apply strategies as follows:
+
+[source,text]
+----
+StrategyA on a
+StrategyA on b
+StrategyA on c
+StrategyA on d
+StrategyB on a
+StrategyB on b
+StrategyB on c
+StrategyB on d
+----
+
+In this way, strategy B can check if it is being applied to the root traversal and if it is it knows that A has been
+applied globally.
+
+This revised methodology could represent a breaking change for `TraversalStrategy` implementations if they somehow
+relied on the old ordering of application. It may also present an opportunity to revise how a `TraversalStrategy` is
+written to gain some processing benefit to the new order. Please be sure to review any custom strategies carefully
+when upgrading to this version.
+
+As part of this change, there have been some adjustments to the `Traversal` and `Traversal.Admin` interfaces which have
+helped to clarify coding intent. There is now an `isRoot()` method which determines whether or not the traversal has a
+parent or not. Under revised semantics for 3.5.0, a traversal's parent must be an `EmptyStep` instance and should not
+be `null`. With this change, provider `TraversalStrategy` implementations should be reviewed to evaluate if `isRoot()`
+semantics cause any breaks in logic to existing code.
+
+In addition, `TraversalStrategies` now implements `Iterable` and exposes an `iterator()` method which may be preferred
+over the old `toList()` style construction for getting the list of configured strategies.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-1568[TINKERPOP-1568],
+link:https://issues.apache.org/jira/browse/TINKERPOP-2310[TINKERPOP-2310],
+link:https://issues.apache.org/jira/browse/TINKERPOP-2311[TINKERPOP-2311]
+
+===== Null Semantics
+
+Graph providers should take note of the changes to `null` semantics described in the "users" section of these upgrade
+notes. As `null` is now acceptable as a `Traverser` object, this change may affect custom steps. Further note that
+`null` now works more consistently with mutation steps and graph providers may need to include additional logic to
+deal with those possible conditions. Please see the console sessions below which uses TinkerGraph to demonstrate the
+current behavioral expectations.
+
+[source,text]
+----
+gremlin> g.getGraph().features().vertex().supportsNullPropertyValues()
+==>false
+gremlin> g.addV(null).property(id, null).property('name',null)
+==>v[0]
+gremlin> g.V().elementMap()
+==>[id:0,label:vertex]
+...
+gremlin> g.getGraph().features().vertex().supportsNullPropertyValues()
+==>true
+gremlin> g.addV(null).property(id, null).property('name',null)
+==>v[0]
+gremlin> g.V().elementMap()
+==>[id:0,label:vertex,name:null]
+----
+
+In the above example, `addV()` defaults to `Vertex.DEFAULT_LABEL`, the `id` is generated and setting the "name"
+property to `null` results in the value not being set. If the property value is set to an actual value and then set
+to `null` TinkerGraph will remove the property key all together:
+
+[source,text]
+----
+gremlin> g.getGraph().features().vertex().supportsNullPropertyValues()
+==>false
+gremlin> g.addV().property('name','stephen')
+==>v[0]
+gremlin> g.V().elementMap()
+==>[id:0,label:vertex,name:stephen]
+gremlin> g.V().has('vertex','name','stephen').property('name',null)
+==>v[0]
+gremlin> g.V().elementMap()
+==>[id:0,label:vertex]
+...
+gremlin> g.getGraph().features().vertex().supportsNullPropertyValues()
+==>true
+gremlin> g.addV().property('name','stephen')
+==>v[2]
+gremlin> g.V().has('vertex','name','stephen').property('name',null)
+==>v[2]
+gremlin> g.V().elementMap()
+==>[id:2,label:vertex,name:null]
+----
+
+The above examples point out the default operations of TinkerGraph, but it can be configured to actually accept the
+`null` as a property value and it is up to graph providers to decided how they wish to treat a `null` property value.
+Providers should use the new `supportsNullPropertyValues()` feature to indicate to users how `null` is handled.
+
+For edges, the `label` still cannot be defaulted and must be specified, therefore:
+
+[source,text]
+----
+gremlin> g.V(0L).as('a').addE(null).to('a')
+Label can not be null
+Type ':help' or ':h' for help.
+Display stack trace? [yN]n
+gremlin> g.V(0L).as('a').addE(constant(null)).to('a')
+Label can not be null
+Type ':help' or ':h' for help.
+Display stack trace? [yN]
+----
+
+Also, edges have similar behavior to vertices when it comes to setting properties (again, the default configuration for
+TinkerGraph is being used here):
+
+[source,text]
+----
+gremlin> g.getGraph().features().vertex().supportsNullPropertyValues()
+==>false
+gremlin> g.addV().property('name','stephen')
+==>v[0]
+gremlin> g.V().has('vertex','name','stephen').as('a').addE('knows').to('a').property(id,null).property('weight',null)
+==>e[2][0-knows->0]
+gremlin> g.E().elementMap()
+==>[id:2,label:knows,IN:[id:0,label:vertex],OUT:[id:0,label:vertex]]
+gremlin> g.E().property('weight',0.5)
+==>e[2][0-knows->0]
+gremlin> g.E().elementMap()
+==>[id:2,label:knows,IN:[id:0,label:vertex],OUT:[id:0,label:vertex],weight:0.5]
+gremlin> g.E().property('weight',null)
+==>e[2][0-knows->0]
+gremlin> g.E().elementMap()
+==>[id:2,label:knows,IN:[id:0,label:vertex],OUT:[id:0,label:vertex]]
+...
+gremlin> g.getGraph().features().vertex().supportsNullPropertyValues()
+==>true
+gremlin> g.addV().property('name','stephen')
+==>v[8]
+gremlin> g.V().has('vertex','name','stephen').as('a').addE('knows').to('a').property(id,null).property('weight',null)
+==>e[10][8-knows->8]
+gremlin> g.E().elementMap()
+==>[id:10,label:knows,IN:[id:8,label:vertex],OUT:[id:8,label:vertex],weight:null]
+gremlin> g.E().property('weight',0.5)
+==>e[10][8-knows->8]
+gremlin> g.E().elementMap()
+==>[id:10,label:knows,IN:[id:8,label:vertex],OUT:[id:8,label:vertex],weight:0.5]
+gremlin> g.E().property('weight',null)
+==>e[10][8-knows->8]
+gremlin> g.E().elementMap()
+==>[id:10,label:knows,IN:[id:8,label:vertex],OUT:[id:8,label:vertex],weight:null]
+----
+
+Graphs that support multi/meta-properties have some issues to consider as well as demonstrated with TinkerGraph:
+
+[source,text]
+----
+gremlin> g.getGraph().features().vertex().supportsNullPropertyValues()
+==>false
+gremlin> g.addV().property(list,'foo',"x").property(list,"foo", null).property(list,'foo','bar')
+==>v[0]
+gremlin> g.V().elementMap()
+==>[id:0,label:vertex,foo:bar]
+gremlin> g.V().valueMap()
+==>[foo:[x,bar]]
+gremlin> g.V().property('foo',null)
+==>v[0]
+gremlin> g.V().valueMap(true)
+==>[id:0,label:vertex]
+...
+gremlin> g.addV().property(list,'foo','bar','x',1,'y',null)
+==>v[0]
+gremlin> g.V().properties('foo').valueMap(true)
+==>[id:1,key:foo,value:bar,x:1]
+gremlin> g.V().properties('foo').property('x',null)
+==>vp[foo->bar]
+gremlin> g.V().properties('foo').valueMap(true)
+==>[id:1,key:foo,value:bar]
+...
+gremlin> g.getGraph().features().vertex().supportsNullPropertyValues()
+==>false
+gremlin> g.addV().property(list,'foo',"x").property(list,"foo", null).property(list,'foo','bar')
+==>v[11]
+gremlin> g.V().elementMap()
+==>[id:11,label:vertex,foo:bar]
+gremlin> g.V().valueMap()
+==>[foo:[x,null,bar]]
+...
+gremlin> g.addV().property(list,'foo','bar','x',1,'y',null)
+==>v[0]
+gremlin> g.V().properties('foo').valueMap(true)
+==>[id:1,key:foo,value:bar,x:1,y:null]
+gremlin> g.V().properties('foo').property('x',null)
+==>vp[foo->bar]
+gremlin> g.V().properties('foo').valueMap(true)
+==>[id:1,key:foo,value:bar,x:null,y:null]
+----
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2235[TINKERPOP-2235],
+link:https://issues.apache.org/jira/browse/TINKERPOP-2099[TINKERPOP-2099]
+
+===== AbstractOpProcessor API Change
+
+The `generateMetaData()` method was removed as it was deprecated in a previous version. There already was a preferred
+method called `generateResultMetaData()` that took an extra `Settings` parameter. To fix compilation issues simply
+replace implementations of the `generateMetaData()` method with `generateResultMetaData()`. Gremlin Server has
+only been calling `generateResultMetaData()` since the deprecation, so this correction should be straightforward.
+
+===== StoreStep and AggregateStep
+
+Note that `StoreStep` has been renamed to `AggregateLocalStep` and `AggregateStep` has been renamed to
+`AggregateGlobalStep`. The renaming is important to consider if any custom `TraversalStrategies` have been written
+that rely on the old step names.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2254[TINKERPOP-2254]
+
+===== Session Close
+
+TinkerPop drivers no longer send the session "close" message to kill a session. The close of the connection itself
+should be responsible for the close of the session. It is also expected that a session is bound to the client that
+created it. Closing the session explicitly by closing the connection will act as a force close where transaction are
+not explicitly rolled-back by Gremlin Server. Such transactions would be handled by the underlying graph system in the
+manner that they provide.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2336[TINKERPOP-2336]
+
+===== TemporaryException and SERVER_ERROR_TEMPORARY
+
+The `gremlin-core` module now has a `TemporaryException` interface. This interface allows providers to throw an
+exception that will be considered by users to be generally retryable. In addition, the Gremlin Server protocol now
+also has a `ResponseStatusCode.SERVER_ERROR_TEMPORARY` status which indicates the same situation. Throwing an exception
+that implements `TemporaryException` will be recognized by Gremlin Server to return this error code. This notion of
+"temporary failure" is helpful to providers as it allows them to let users know that a failure is transient and related
+to the system state at the time of the request. Without this indicator, users are left to parse exception messages to
+determine when it is considered acceptable to retry an operation.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2517[TINKERPOP-2517]
+
+===== gremlin-language
+
+The new `gremlin-language` module contains an ANTLR4 grammar for the Gremlin language along with the generated parser
+code. The grammar is still under development but covers most of the Gremlin language, with the idea that it will
+eventually drive the ongoing design of the language, as opposed to driving it from Java.
+
+The grammar is currently tested against the Gremlin traversals in the entire Gherkin test suite, as well as a major
+portion of the Gremlin used for examples in the Reference Documentation. The grammar has the following limitations:
+
+* It does not support lambdas or Groovy syntax
+* The following steps are not yet fully supported:
+** `withComputer()`
+** `io()`
+** `withoutStrategies()`
+** `program()`
+** `connectedComponent()`
+** `fill()` terminator step
+* `Vertex` and `Edge` instance definitions
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2533[https://issues.apache.org/jira/browse/TINKERPOP-2533]
+
+===== UnifiedChannelizer
+
+The `UnifiedChannelizer` is a new `Channelizer` implementation. It exposes new a new `Session` interface that allows
+this channelizer to be extended with custom functionality specific to a providers environment. As of 3.5.0, this
+channelizer is not the default and only fits certain workload patterns. The interfaces should therefore be considered
+volatile and may change.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2245[TINKERPOP-2245]
+
+==== Graph Driver Providers
+
+===== TraversalOpProcessor Side-effects
+
+`TraversalOpProcessor` no longer holds a cache of side-effects and more generally the entire side-effect protocol has
+been removed and is no longer supported in the server or drivers.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2269[TINKERPOP-2269]
+
+===== Close Message
+
+The functionality of the "close" message is no longer in place in Gremlin Server. Sending the message (from older
+drivers for example) will simply result in a no-op on the server and the expected return of the `NO_CONTENT` message.
+From 3.5.0 forward, drivers need not send this message to close the session and simply rely on the close of the
+connection to kill the session.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2336[TINKERPOP-2336]
\ No newline at end of file
diff --git a/docs/static/images/gremlin-sleeping-beauty.png b/docs/static/images/gremlin-sleeping-beauty.png
new file mode 100644
index 0000000..3095da3
--- /dev/null
+++ b/docs/static/images/gremlin-sleeping-beauty.png
Binary files differ
diff --git a/gremlin-archetype/gremlin-archetype-dsl/pom.xml b/gremlin-archetype/gremlin-archetype-dsl/pom.xml
index 3f3502f..8105d99 100644
--- a/gremlin-archetype/gremlin-archetype-dsl/pom.xml
+++ b/gremlin-archetype/gremlin-archetype-dsl/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.apache.tinkerpop</groupId>
         <artifactId>gremlin-archetype</artifactId>
-        <version>3.4.12-SNAPSHOT</version>
+        <version>3.5.1-SNAPSHOT</version>
     </parent>
 
     <artifactId>gremlin-archetype-dsl</artifactId>
diff --git a/gremlin-archetype/gremlin-archetype-dsl/src/main/resources/archetype-resources/README.asciidoc b/gremlin-archetype/gremlin-archetype-dsl/src/main/resources/archetype-resources/README.asciidoc
index 49fd7c8..1471018 100644
--- a/gremlin-archetype/gremlin-archetype-dsl/src/main/resources/archetype-resources/README.asciidoc
+++ b/gremlin-archetype/gremlin-archetype-dsl/src/main/resources/archetype-resources/README.asciidoc
@@ -23,8 +23,8 @@
 
 == Prerequisites
 
-* Java 8 Update 40+
-* link:https://maven.apache.org/[Maven 3.x]
+* Java 11
+* link:https://maven.apache.org/[Maven 3.3+]
 
 == Building and Running
 
diff --git a/gremlin-archetype/gremlin-archetype-dsl/src/main/resources/archetype-resources/pom.xml b/gremlin-archetype/gremlin-archetype-dsl/src/main/resources/archetype-resources/pom.xml
index d7bb31c..282779f 100644
--- a/gremlin-archetype/gremlin-archetype-dsl/src/main/resources/archetype-resources/pom.xml
+++ b/gremlin-archetype/gremlin-archetype-dsl/src/main/resources/archetype-resources/pom.xml
@@ -49,15 +49,41 @@
     <build>
         <plugins>
             <plugin>
-                <!-- TinkerPop3 requires Java 8 -->
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
-                <version>3.3</version>
+                <version>3.8.0</version>
                 <configuration>
                     <source>1.8</source>
                     <target>1.8</target>
+                    <compilerArgs>
+                        <arg>-parameters</arg>
+                    </compilerArgs>
                 </configuration>
             </plugin>
         </plugins>
     </build>
+
+    <profiles>
+        <profile>
+            <id>jdk11</id>
+            <activation>
+                <jdk>11</jdk>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-compiler-plugin</artifactId>
+                        <version>3.8.1</version>
+                        <configuration>
+                            <release>8</release>
+                            <compilerArgs>
+                                <arg>-parameters</arg>
+                            </compilerArgs>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
 </project>
\ No newline at end of file
diff --git a/gremlin-archetype/gremlin-archetype-server/pom.xml b/gremlin-archetype/gremlin-archetype-server/pom.xml
index fce2671..6ce7bb7 100644
--- a/gremlin-archetype/gremlin-archetype-server/pom.xml
+++ b/gremlin-archetype/gremlin-archetype-server/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.apache.tinkerpop</groupId>
         <artifactId>gremlin-archetype</artifactId>
-        <version>3.4.12-SNAPSHOT</version>
+        <version>3.5.1-SNAPSHOT</version>
     </parent>
 
     <artifactId>gremlin-archetype-server</artifactId>
diff --git a/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/README.asciidoc b/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/README.asciidoc
index d4a0eb1..9daafb2 100644
--- a/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/README.asciidoc
+++ b/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/README.asciidoc
@@ -24,8 +24,8 @@
 
 == Prerequisites
 
-* Java 8 Update 40+
-* link:https://maven.apache.org/[Maven 3.x]
+* Java 11
+* link:https://maven.apache.org/[Maven 3.3+]
 * Gremlin Server is link:http://archive.apache.org/dist/tinkerpop/[downloaded] and unpackaged
 
 == Building and Running
diff --git a/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/pom.xml b/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/pom.xml
index ca29604..3f4945b 100644
--- a/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/pom.xml
+++ b/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/pom.xml
@@ -55,19 +55,21 @@
     <build>
         <plugins>
             <plugin>
-                <!-- TinkerPop3 requires Java 8 -->
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
-                <version>3.3</version>
+                <version>3.8.0</version>
                 <configuration>
                     <source>1.8</source>
                     <target>1.8</target>
+                    <compilerArgs>
+                        <arg>-parameters</arg>
+                    </compilerArgs>
                 </configuration>
             </plugin>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-surefire-plugin</artifactId>
-                <version>2.17</version>
+                <version>2.22.0</version>
                 <configuration>
                     <systemPropertyVariables>
                         <log4j.configuration>file:conf/log4j-test.properties</log4j.configuration>
@@ -76,4 +78,28 @@
             </plugin>
         </plugins>
     </build>
+
+    <profiles>
+        <profile>
+            <id>jdk11</id>
+            <activation>
+                <jdk>11</jdk>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-compiler-plugin</artifactId>
+                        <version>3.8.1</version>
+                        <configuration>
+                            <release>8</release>
+                            <compilerArgs>
+                                <arg>-parameters</arg>
+                            </compilerArgs>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
 </project>
\ No newline at end of file
diff --git a/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/src/test/java/ServiceTest.java b/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/src/test/java/ServiceTest.java
index cc3feaa..6f4439f 100644
--- a/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/src/test/java/ServiceTest.java
+++ b/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/src/test/java/ServiceTest.java
@@ -31,7 +31,7 @@
 import org.junit.Test;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.CoreMatchers.is;
 
 /**
diff --git a/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/src/test/resources/gremlin-server.yaml b/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/src/test/resources/gremlin-server.yaml
index 9530b50..3ba912d 100644
--- a/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/src/test/resources/gremlin-server.yaml
+++ b/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/src/test/resources/gremlin-server.yaml
@@ -28,8 +28,7 @@
                org.apache.tinkerpop.gremlin.tinkergraph.jsr223.TinkerGraphGremlinPlugin: {},
                org.apache.tinkerpop.gremlin.jsr223.ScriptFileGremlinPlugin: {files: [scripts/generate-modern.groovy]}}}}
 serializers:
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3d0]}}
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0, config: { serializeResultToString: true }}                                                                                                                                                                # application/vnd.gremlin-v1.0+gryo-stringd
+  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1 }
 metrics: {
   slf4jReporter: {enabled: true, interval: 180000}}
 strictTransactionManagement: false
diff --git a/gremlin-archetype/gremlin-archetype-tinkergraph/pom.xml b/gremlin-archetype/gremlin-archetype-tinkergraph/pom.xml
index 4e1fde2..e188d0d 100644
--- a/gremlin-archetype/gremlin-archetype-tinkergraph/pom.xml
+++ b/gremlin-archetype/gremlin-archetype-tinkergraph/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.apache.tinkerpop</groupId>
         <artifactId>gremlin-archetype</artifactId>
-        <version>3.4.12-SNAPSHOT</version>
+        <version>3.5.1-SNAPSHOT</version>
     </parent>
 
     <artifactId>gremlin-archetype-tinkergraph</artifactId>
diff --git a/gremlin-archetype/gremlin-archetype-tinkergraph/src/main/resources/archetype-resources/README.asciidoc b/gremlin-archetype/gremlin-archetype-tinkergraph/src/main/resources/archetype-resources/README.asciidoc
index ddb6de6..6535647 100644
--- a/gremlin-archetype/gremlin-archetype-tinkergraph/src/main/resources/archetype-resources/README.asciidoc
+++ b/gremlin-archetype/gremlin-archetype-tinkergraph/src/main/resources/archetype-resources/README.asciidoc
@@ -22,8 +22,8 @@
 
 == Prerequisites
 
-* Java 8 Update 40+
-* link:https://maven.apache.org/[Maven 3.x]
+* Java 11
+* link:https://maven.apache.org/[Maven 3.3+]
 
 == Building and Running
 
diff --git a/gremlin-archetype/gremlin-archetype-tinkergraph/src/main/resources/archetype-resources/pom.xml b/gremlin-archetype/gremlin-archetype-tinkergraph/src/main/resources/archetype-resources/pom.xml
index 0727319..6f1ebed 100644
--- a/gremlin-archetype/gremlin-archetype-tinkergraph/src/main/resources/archetype-resources/pom.xml
+++ b/gremlin-archetype/gremlin-archetype-tinkergraph/src/main/resources/archetype-resources/pom.xml
@@ -49,15 +49,41 @@
     <build>
         <plugins>
             <plugin>
-                <!-- TinkerPop3 requires Java 8 -->
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
-                <version>3.3</version>
+                <version>3.8.0</version>
                 <configuration>
                     <source>1.8</source>
                     <target>1.8</target>
+                    <compilerArgs>
+                        <arg>-parameters</arg>
+                    </compilerArgs>
                 </configuration>
             </plugin>
         </plugins>
     </build>
+
+    <profiles>
+        <profile>
+            <id>jdk11</id>
+            <activation>
+                <jdk>11</jdk>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-compiler-plugin</artifactId>
+                        <version>3.8.1</version>
+                        <configuration>
+                            <release>8</release>
+                            <compilerArgs>
+                                <arg>-parameters</arg>
+                            </compilerArgs>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
 </project>
\ No newline at end of file
diff --git a/gremlin-archetype/pom.xml b/gremlin-archetype/pom.xml
index ea3f953..f13f6ad 100644
--- a/gremlin-archetype/pom.xml
+++ b/gremlin-archetype/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>tinkerpop</artifactId>
         <groupId>org.apache.tinkerpop</groupId>
-        <version>3.4.12-SNAPSHOT</version>
+        <version>3.5.1-SNAPSHOT</version>
     </parent>
 
     <artifactId>gremlin-archetype</artifactId>
diff --git a/gremlin-console/Dockerfile b/gremlin-console/Dockerfile
index ff57227..3291d69 100644
--- a/gremlin-console/Dockerfile
+++ b/gremlin-console/Dockerfile
@@ -15,7 +15,7 @@
 # specific language governing permissions and limitations
 # under the License.
 
-FROM openjdk:8-jre-alpine
+FROM adoptopenjdk/openjdk11:alpine-slim
 
 LABEL maintainer="dev@tinkerpop.apache.org"
 
diff --git a/gremlin-console/bin/gremlin.sh b/gremlin-console/bin/gremlin.sh
index fa4160f..e9eee65 120000
--- a/gremlin-console/bin/gremlin.sh
+++ b/gremlin-console/bin/gremlin.sh
@@ -1 +1 @@
-../target/apache-tinkerpop-gremlin-console-3.4.12-SNAPSHOT-standalone/bin/gremlin.sh
\ No newline at end of file
+../target/apache-tinkerpop-gremlin-console-3.5.1-SNAPSHOT-standalone/bin/gremlin.sh
\ No newline at end of file
diff --git a/gremlin-console/pom.xml b/gremlin-console/pom.xml
index b7f5fd3..45928d6 100644
--- a/gremlin-console/pom.xml
+++ b/gremlin-console/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>tinkerpop</artifactId>
         <groupId>org.apache.tinkerpop</groupId>
-        <version>3.4.12-SNAPSHOT</version>
+        <version>3.5.1-SNAPSHOT</version>
     </parent>
     <artifactId>gremlin-console</artifactId>
     <name>Apache TinkerPop :: Gremlin Console</name>
@@ -68,7 +68,7 @@
         </dependency>
         <dependency>
             <groupId>org.hamcrest</groupId>
-            <artifactId>hamcrest-all</artifactId>
+            <artifactId>hamcrest</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>
@@ -223,8 +223,6 @@
                             <createSourcesJar>true</createSourcesJar>
                             <relocations>
                                 <relocation>
-                                    <pattern>com.google.guava</pattern>
-                                    <shadedPattern>com.shaded.google.guava</shadedPattern>
                                     <pattern>io.netty</pattern>
                                     <shadedPattern>io.shaded.netty</shadedPattern>
                                 </relocation>
@@ -339,6 +337,14 @@
                                         <copy todir="${project.build.directory}/python">
                                             <fileset dir="src/test/python"/>
                                         </copy>
+                                        <exec dir="${project.build.directory}/python" executable="python3"
+                                              failonerror="true">
+                                            <arg line="--version"/>
+                                        </exec>
+                                        <exec dir="${project.build.directory}/python" executable="virtualenv"
+                                              failonerror="true">
+                                            <arg line="--version"/>
+                                        </exec>
                                         <exec dir="${project.build.directory}/python" executable="virtualenv"
                                               failonerror="true">
                                             <arg line="--python=python3 env"/>
diff --git a/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/commands/BytecodeCommand.groovy b/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/commands/BytecodeCommand.groovy
index 3718202..ca966e5 100644
--- a/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/commands/BytecodeCommand.groovy
+++ b/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/commands/BytecodeCommand.groovy
@@ -23,7 +23,6 @@
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal
 import org.apache.tinkerpop.gremlin.process.traversal.translator.GroovyTranslator
 import org.apache.tinkerpop.gremlin.structure.io.IoRegistry
-import org.apache.tinkerpop.gremlin.structure.io.Mapper
 import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper
 import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONVersion
 import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONXModuleV3d0
diff --git a/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/jsr223/GephiTraversalVisualizationStrategy.groovy b/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/jsr223/GephiTraversalVisualizationStrategy.groovy
index 5e44800..4cb8ffd 100644
--- a/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/jsr223/GephiTraversalVisualizationStrategy.groovy
+++ b/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/jsr223/GephiTraversalVisualizationStrategy.groovy
@@ -28,7 +28,7 @@
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.EdgeVertexStep
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.GraphStep
 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.AggregateGlobalStep
 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.strategy.AbstractTraversalStrategy
@@ -91,7 +91,7 @@
                         Thread.sleep(acceptor.vizStepDelay)
                     }
                 }), s, traversal)
-                TraversalHelper.insertAfterStep(new AggregateStep(traversal, sideEffectKey), s, traversal)
+                TraversalHelper.insertAfterStep(new AggregateGlobalStep(traversal, sideEffectKey), s, traversal)
             }
 
             // decay all vertices except those that made it through the filter - "this way you can watch
@@ -109,7 +109,7 @@
                         Thread.sleep(acceptor.vizStepDelay)
                     }
                 }), s, traversal)
-                TraversalHelper.insertAfterStep(new AggregateStep(traversal, sideEffectKey), s, traversal)
+                TraversalHelper.insertAfterStep(new AggregateGlobalStep(traversal, sideEffectKey), s, traversal)
             }
         }
     }
diff --git a/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/jsr223/DriverGremlinPlugin.java b/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/jsr223/DriverGremlinPlugin.java
index 80a78ab..2f12c4c 100644
--- a/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/jsr223/DriverGremlinPlugin.java
+++ b/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/jsr223/DriverGremlinPlugin.java
@@ -35,7 +35,6 @@
 import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
 import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection;
 import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteTraversal;
-import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteTraversalSideEffects;
 import org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1;
 import org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV1d0;
 import org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV2d0;
@@ -93,8 +92,7 @@
                     Serializers.class,
                     SerTokens.class,
                     DriverRemoteConnection.class,
-                    DriverRemoteTraversal.class,
-                    DriverRemoteTraversalSideEffects.class).create();
+                    DriverRemoteTraversal.class).create();
 
     public DriverGremlinPlugin() {
         super(NAME, imports, new DriverConsoleCustomizer());
diff --git a/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/jsr223/DriverRemoteAcceptorIntegrateTest.java b/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/jsr223/DriverRemoteAcceptorIntegrateTest.java
index 3a64b98..33499d5 100644
--- a/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/jsr223/DriverRemoteAcceptorIntegrateTest.java
+++ b/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/jsr223/DriverRemoteAcceptorIntegrateTest.java
@@ -45,7 +45,7 @@
 import static org.hamcrest.Matchers.contains;
 import static org.hamcrest.Matchers.hasSize;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.fail;
 
 /**
diff --git a/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/jsr223/DriverRemoteAcceptorTest.java b/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/jsr223/DriverRemoteAcceptorTest.java
index ab11d2e..ffa8385 100644
--- a/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/jsr223/DriverRemoteAcceptorTest.java
+++ b/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/jsr223/DriverRemoteAcceptorTest.java
@@ -32,7 +32,7 @@
 
 import static org.hamcrest.CoreMatchers.startsWith;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 
 /**
  * @author Stephen Mallette (http://stephen.genoprime.com)
diff --git a/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/jsr223/GephiRemoteAcceptorIntegrateTest.java b/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/jsr223/GephiRemoteAcceptorIntegrateTest.java
index b1f8eff..9e2a024 100644
--- a/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/jsr223/GephiRemoteAcceptorIntegrateTest.java
+++ b/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/jsr223/GephiRemoteAcceptorIntegrateTest.java
@@ -49,7 +49,7 @@
 import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
 import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo;
 import static org.hamcrest.CoreMatchers.startsWith;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 
 /**
  * @author Stephen Mallette (http://stephen.genoprime.com)
diff --git a/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/jsr223/UtilitiesGremlinPluginTest.java b/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/jsr223/UtilitiesGremlinPluginTest.java
index 385e086..07fd951 100644
--- a/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/jsr223/UtilitiesGremlinPluginTest.java
+++ b/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/jsr223/UtilitiesGremlinPluginTest.java
@@ -30,7 +30,7 @@
 import java.io.OutputStream;
 
 import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.fail;
 
 /**
diff --git a/gremlin-core/pom.xml b/gremlin-core/pom.xml
index f343b6f..0c359f6 100644
--- a/gremlin-core/pom.xml
+++ b/gremlin-core/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>org.apache.tinkerpop</groupId>
         <artifactId>tinkerpop</artifactId>
-        <version>3.4.12-SNAPSHOT</version>
+        <version>3.5.1-SNAPSHOT</version>
     </parent>
     <artifactId>gremlin-core</artifactId>
     <name>Apache TinkerPop :: Gremlin Core</name>
@@ -31,8 +31,12 @@
             <version>${project.version}</version>
         </dependency>
         <dependency>
-            <groupId>commons-configuration</groupId>
-            <artifactId>commons-configuration</artifactId>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-configuration2</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-beanutils</groupId>
+            <artifactId>commons-beanutils</artifactId>
         </dependency>
         <dependency>
             <groupId>commons-collections</groupId>
@@ -43,6 +47,10 @@
             <artifactId>commons-lang3</artifactId>
         </dependency>
         <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-text</artifactId>
+        </dependency>
+        <dependency>
             <groupId>org.yaml</groupId>
             <artifactId>snakeyaml</artifactId>
             <version>${snakeyaml.version}</version>
@@ -105,13 +113,42 @@
         </dependency>
         <dependency>
             <groupId>org.hamcrest</groupId>
-            <artifactId>hamcrest-all</artifactId>
+            <artifactId>hamcrest</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>com.google.testing.compile</groupId>
             <artifactId>compile-testing</artifactId>
-            <version>0.10</version>
+            <version>0.15</version>
+            <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.google.guava</groupId>
+                    <artifactId>guava</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>com.google.errorprone</groupId>
+                    <artifactId>error_prone_annotations</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <!-- resolve self-conflict within compile-testing -->
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+            <version>23.4-android</version>
+            <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.google.errorprone</groupId>
+                    <artifactId>error_prone_annotations</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>com.google.errorprone</groupId>
+            <artifactId>error_prone_annotations</artifactId>
+            <version>2.0.19</version>
             <scope>test</scope>
             <exclusions>
               <exclusion>
@@ -154,4 +191,31 @@
             </plugin>
         </plugins>
     </build>
+
+    <profiles>
+        <profile>
+            <id>jdk11</id>
+            <activation>
+                <jdk>11</jdk>
+            </activation>
+            <build>
+                <pluginManagement>
+                    <plugins>
+                        <plugin>
+                            <groupId>org.apache.maven.plugins</groupId>
+                            <artifactId>maven-compiler-plugin</artifactId>
+                            <version>3.8.1</version>
+                            <configuration>
+                                <release>8</release>
+                                <compilerArgs>
+                                    <arg>-parameters</arg>
+                                    <arg>-proc:none</arg>
+                                </compilerArgs>
+                            </configuration>
+                        </plugin>
+                    </plugins>
+                </pluginManagement>
+            </build>
+        </profile>
+    </profiles>
 </project>
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java
index 1863c2a..2897506 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java
@@ -19,28 +19,22 @@
 
 package org.apache.tinkerpop.gremlin.jsr223;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.CombinedConfiguration;
-import org.apache.commons.configuration.CompositeConfiguration;
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.ConfigurationBuilder;
-import org.apache.commons.configuration.ConfigurationUtils;
-import org.apache.commons.configuration.FileConfiguration;
-import org.apache.commons.configuration.HierarchicalConfiguration;
-import org.apache.commons.configuration.MapConfiguration;
-import org.apache.commons.configuration.PropertiesConfiguration;
-import org.apache.commons.configuration.SubsetConfiguration;
-import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.CombinedConfiguration;
+import org.apache.commons.configuration2.CompositeConfiguration;
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.configuration2.ConfigurationUtils;
+import org.apache.commons.configuration2.HierarchicalConfiguration;
+import org.apache.commons.configuration2.MapConfiguration;
+import org.apache.commons.configuration2.PropertiesConfiguration;
+import org.apache.commons.configuration2.SubsetConfiguration;
+import org.apache.commons.configuration2.XMLConfiguration;
+import org.apache.commons.configuration2.builder.fluent.Configurations;
 import org.apache.tinkerpop.gremlin.process.computer.Computer;
 import org.apache.tinkerpop.gremlin.process.computer.ComputerResult;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
 import org.apache.tinkerpop.gremlin.process.computer.Memory;
 import org.apache.tinkerpop.gremlin.process.computer.VertexProgram;
-import org.apache.tinkerpop.gremlin.process.computer.bulkdumping.BulkDumperVertexProgram;
-import org.apache.tinkerpop.gremlin.process.computer.bulkloading.BulkLoader;
-import org.apache.tinkerpop.gremlin.process.computer.bulkloading.BulkLoaderVertexProgram;
-import org.apache.tinkerpop.gremlin.process.computer.bulkloading.IncrementalBulkLoader;
-import org.apache.tinkerpop.gremlin.process.computer.bulkloading.OneTimeBulkLoader;
 import org.apache.tinkerpop.gremlin.process.computer.clone.CloneVertexProgram;
 import org.apache.tinkerpop.gremlin.process.computer.clustering.connected.ConnectedComponentVertexProgram;
 import org.apache.tinkerpop.gremlin.process.computer.clustering.peerpressure.ClusterCountMapReduce;
@@ -57,6 +51,7 @@
 import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.ShortestPath;
 import org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy;
 import org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.optimization.GraphFilterStrategy;
+import org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.verification.VertexProgramRestrictionStrategy;
 import org.apache.tinkerpop.gremlin.process.remote.RemoteConnection;
 import org.apache.tinkerpop.gremlin.process.traversal.Bindings;
 import org.apache.tinkerpop.gremlin.process.traversal.IO;
@@ -85,6 +80,7 @@
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization.MatchAlgorithmStrategy;
 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.ByModulatorOptimizationStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.EarlyLimitStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.FilterRankingStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.IdentityRemovalStrategy;
@@ -99,6 +95,10 @@
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.LambdaRestrictionStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.StandardVerificationStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.translator.DotNetTranslator;
+import org.apache.tinkerpop.gremlin.process.traversal.translator.GroovyTranslator;
+import org.apache.tinkerpop.gremlin.process.traversal.translator.JavascriptTranslator;
+import org.apache.tinkerpop.gremlin.process.traversal.translator.PythonTranslator;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalMetrics;
 import org.apache.tinkerpop.gremlin.structure.Column;
 import org.apache.tinkerpop.gremlin.structure.Direction;
@@ -234,14 +234,13 @@
         CLASS_IMPORTS.add(CombinedConfiguration.class);
         CLASS_IMPORTS.add(CompositeConfiguration.class);
         CLASS_IMPORTS.add(Configuration.class);
-        CLASS_IMPORTS.add(ConfigurationBuilder.class);
         CLASS_IMPORTS.add(ConfigurationUtils.class);
-        CLASS_IMPORTS.add(FileConfiguration.class);
         CLASS_IMPORTS.add(HierarchicalConfiguration.class);
         CLASS_IMPORTS.add(MapConfiguration.class);
         CLASS_IMPORTS.add(PropertiesConfiguration.class);
         CLASS_IMPORTS.add(SubsetConfiguration.class);
         CLASS_IMPORTS.add(XMLConfiguration.class);
+        CLASS_IMPORTS.add(Configurations.class);
         // strategies
         CLASS_IMPORTS.add(ConnectiveStrategy.class);
         CLASS_IMPORTS.add(ElementIdStrategy.class);
@@ -253,6 +252,8 @@
         CLASS_IMPORTS.add(MatchAlgorithmStrategy.class);
         CLASS_IMPORTS.add(ProfileStrategy.class);
         CLASS_IMPORTS.add(AdjacentToIncidentStrategy.class);
+        CLASS_IMPORTS.add(ByModulatorOptimizationStrategy.class);
+        CLASS_IMPORTS.add(CountStrategy.class);
         CLASS_IMPORTS.add(FilterRankingStrategy.class);
         CLASS_IMPORTS.add(IdentityRemovalStrategy.class);
         CLASS_IMPORTS.add(IncidentToAdjacentStrategy.class);
@@ -260,13 +261,13 @@
         CLASS_IMPORTS.add(EarlyLimitStrategy.class);
         CLASS_IMPORTS.add(OrderLimitStrategy.class);
         CLASS_IMPORTS.add(PathProcessorStrategy.class);
-        CLASS_IMPORTS.add(CountStrategy.class);
         CLASS_IMPORTS.add(ComputerVerificationStrategy.class);
         CLASS_IMPORTS.add(LambdaRestrictionStrategy.class);
         CLASS_IMPORTS.add(ReadOnlyStrategy.class);
         CLASS_IMPORTS.add(ReferenceElementStrategy.class);
         CLASS_IMPORTS.add(StandardVerificationStrategy.class);
         CLASS_IMPORTS.add(EdgeLabelVerificationStrategy.class);
+        CLASS_IMPORTS.add(VertexProgramRestrictionStrategy.class);
         // graph traversal
         CLASS_IMPORTS.add(AnonymousTraversalSource.class);
         CLASS_IMPORTS.add(__.class);
@@ -275,6 +276,11 @@
         CLASS_IMPORTS.add(Traversal.class);
         CLASS_IMPORTS.add(TraversalMetrics.class);
         CLASS_IMPORTS.add(Translator.class);
+        CLASS_IMPORTS.add(DotNetTranslator.class);
+        CLASS_IMPORTS.add(GroovyTranslator.class);
+        CLASS_IMPORTS.add(JavaTranslator.class);
+        CLASS_IMPORTS.add(JavascriptTranslator.class);
+        CLASS_IMPORTS.add(PythonTranslator.class);
         CLASS_IMPORTS.add(Bindings.class);
         // graph computer
         CLASS_IMPORTS.add(Computer.class);
@@ -285,11 +291,6 @@
         CLASS_IMPORTS.add(Memory.class);
         CLASS_IMPORTS.add(VertexProgram.class);
         CLASS_IMPORTS.add(CloneVertexProgram.class);
-        CLASS_IMPORTS.add(BulkDumperVertexProgram.class);
-        CLASS_IMPORTS.add(BulkLoader.class);
-        CLASS_IMPORTS.add(BulkLoaderVertexProgram.class);
-        CLASS_IMPORTS.add(IncrementalBulkLoader.class);
-        CLASS_IMPORTS.add(OneTimeBulkLoader.class);
         CLASS_IMPORTS.add(ClusterCountMapReduce.class);
         CLASS_IMPORTS.add(ClusterPopulationMapReduce.class);
         CLASS_IMPORTS.add(MemoryTraversalSideEffects.class);
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/JavaTranslator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/JavaTranslator.java
index 3bb605e..7adf87f 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/JavaTranslator.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/JavaTranslator.java
@@ -19,8 +19,8 @@
 
 package org.apache.tinkerpop.gremlin.jsr223;
 
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.MapConfiguration;
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.configuration2.MapConfiguration;
 import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
 import org.apache.tinkerpop.gremlin.process.traversal.Translator;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
@@ -28,6 +28,7 @@
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.BulkSet;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.TraversalStrategyProxy;
+import org.apache.tinkerpop.gremlin.process.traversal.util.BytecodeHelper;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 
 import java.lang.reflect.Array;
@@ -35,7 +36,6 @@
 import java.lang.reflect.Method;
 import java.lang.reflect.Parameter;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
@@ -43,7 +43,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.StringJoiner;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
@@ -76,6 +75,9 @@
 
     @Override
     public T translate(final Bytecode bytecode) {
+        if (BytecodeHelper.isGraphOperation(bytecode))
+            throw new IllegalArgumentException("JavaTranslator cannot translate traversal operations");
+
         TraversalSource dynamicSource = this.traversalSource;
         Traversal.Admin<?, ?> traversal = null;
         for (final Bytecode.Instruction instruction : bytecode.getSourceInstructions()) {
@@ -217,7 +219,7 @@
                         for (int i = 0; i < parameters.length; i++) {
                             if (parameters[i].isVarArgs()) {
                                 final Class<?> parameterClass = parameters[i].getType().getComponentType();
-                                if (argumentsCopy.length > i && !parameterClass.isAssignableFrom(argumentsCopy[i].getClass())) {
+                                if (argumentsCopy.length > i && argumentsCopy[i] != null && !parameterClass.isAssignableFrom(argumentsCopy[i].getClass())) {
                                     found = false;
                                     break;
                                 }
@@ -229,13 +231,34 @@
                                 newArguments[i] = varArgs;
                                 break;
                             } else {
-                                if (i < argumentsCopy.length &&
-                                        (parameters[i].getType().isAssignableFrom(argumentsCopy[i].getClass()) ||
+                                // try to detect the right method by comparing the type of the parameter to the type
+                                // of the argument. doesn't always work so well because of null arguments which don't
+                                // bring their type in bytecode and rely on position. this doesn't seem to happen often
+                                // ...luckily...because method signatures tend to be sufficiently unique and do not
+                                // encourage whacky use - like g.V().has(null, null) is clearly invalid so we don't
+                                // even need to try to sort that out. on the other hand g.V().has('name',null) which
+                                // is valid hits like four different possible overloads, but we can rely on the most
+                                // generic one which takes Object as the second parameter. that seems to work in this
+                                // case, but it's a shame this isn't nicer. seems like nicer would mean a heavy
+                                // overhaul to Gremlin or to GLVs/bytecode and/or to serialization mechanisms.
+                                //
+                                // the check where argumentsCopy[i] is null could be accompanied by a type check for
+                                // allowable signatures like:
+                                // null == argumentsCopy[i] && parameters[i].getType() == Object.class
+                                // but that doesn't seem helpful. perhaps this approach is fine as long as we ensure
+                                // consistency of null calls to all overloads. in other words addV(String) must behave
+                                // the same as addV(Traversal) if null is used as the argument. so far, that seems to
+                                // be the case. if we find that is not happening we either fix that specific
+                                // inconsistency, start special casing those method finds here, or as mentioned above
+                                // do something far more drastic that doesn't involve reflection.
+                                if (i < argumentsCopy.length && (null == argumentsCopy[i] ||
+                                        (argumentsCopy[i] != null && (
+                                        parameters[i].getType().isAssignableFrom(argumentsCopy[i].getClass()) ||
                                                 (parameters[i].getType().isPrimitive() &&
                                                         (Number.class.isAssignableFrom(argumentsCopy[i].getClass()) ||
                                                                 argumentsCopy[i].getClass().equals(Boolean.class) ||
                                                                 argumentsCopy[i].getClass().equals(Byte.class) ||
-                                                                argumentsCopy[i].getClass().equals(Character.class))))) {
+                                                                argumentsCopy[i].getClass().equals(Character.class))))))) {
                                     newArguments[i] = argumentsCopy[i];
                                 } else {
                                     found = false;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/MapReduce.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/MapReduce.java
index 60a8ad3..05996af 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/MapReduce.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/MapReduce.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.process.computer;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.process.computer.util.DefaultComputerResult;
 import org.apache.tinkerpop.gremlin.structure.Graph;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/VertexProgram.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/VertexProgram.java
index 5637740..682ca5b 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/VertexProgram.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/VertexProgram.java
@@ -19,7 +19,7 @@
 
 package org.apache.tinkerpop.gremlin.process.computer;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
 import org.apache.tinkerpop.gremlin.structure.Element;
 import org.apache.tinkerpop.gremlin.structure.Graph;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/bulkdumping/BulkDumperVertexProgram.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/bulkdumping/BulkDumperVertexProgram.java
deleted file mode 100644
index f70fcc2..0000000
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/bulkdumping/BulkDumperVertexProgram.java
+++ /dev/null
@@ -1,101 +0,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.
- */
-package org.apache.tinkerpop.gremlin.process.computer.bulkdumping;
-
-import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
-import org.apache.tinkerpop.gremlin.process.computer.Memory;
-import org.apache.tinkerpop.gremlin.process.computer.MessageScope;
-import org.apache.tinkerpop.gremlin.process.computer.Messenger;
-import org.apache.tinkerpop.gremlin.process.computer.VertexProgram;
-import org.apache.tinkerpop.gremlin.process.computer.clone.CloneVertexProgram;
-import org.apache.tinkerpop.gremlin.process.computer.util.AbstractVertexProgramBuilder;
-import org.apache.tinkerpop.gremlin.structure.Graph;
-import org.apache.tinkerpop.gremlin.structure.Vertex;
-import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
-import org.javatuples.Tuple;
-
-import java.util.Collections;
-import java.util.Set;
-
-/**
- * @author Daniel Kuppitz (http://gremlin.guru)
- * @deprecated As of release 3.2.10, replaced by {@link CloneVertexProgram}.
- */
-@Deprecated
-public class BulkDumperVertexProgram implements VertexProgram<Tuple> {
-
-    private BulkDumperVertexProgram() {
-    }
-
-    @Override
-    public void setup(final Memory memory) {
-    }
-
-    @Override
-    public void execute(final Vertex sourceVertex, final Messenger<Tuple> messenger, final Memory memory) {
-    }
-
-    @Override
-    public boolean terminate(final Memory memory) {
-        return true;
-    }
-
-    @Override
-    public Set<MessageScope> getMessageScopes(final Memory memory) {
-        return Collections.emptySet();
-    }
-
-    @SuppressWarnings({"CloneDoesntDeclareCloneNotSupportedException", "CloneDoesntCallSuperClone"})
-    @Override
-    public VertexProgram<Tuple> clone() {
-        return this;
-    }
-
-    @Override
-    public GraphComputer.ResultGraph getPreferredResultGraph() {
-        return GraphComputer.ResultGraph.NEW;
-    }
-
-    @Override
-    public GraphComputer.Persist getPreferredPersist() {
-        return GraphComputer.Persist.EDGES;
-    }
-
-    @Override
-    public String toString() {
-        return StringFactory.vertexProgramString(this);
-    }
-
-    public static Builder build() {
-        return new Builder();
-    }
-
-    public static class Builder extends AbstractVertexProgramBuilder<Builder> {
-
-        private Builder() {
-            super(BulkDumperVertexProgram.class);
-        }
-
-        @SuppressWarnings("unchecked")
-        @Override
-        public BulkDumperVertexProgram create(final Graph graph) {
-            return (BulkDumperVertexProgram) VertexProgram.createVertexProgram(graph, configuration);
-        }
-    }
-}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/bulkloading/BulkLoader.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/bulkloading/BulkLoader.java
deleted file mode 100644
index 3767f73..0000000
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/bulkloading/BulkLoader.java
+++ /dev/null
@@ -1,144 +0,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.
- */
-package org.apache.tinkerpop.gremlin.process.computer.bulkloading;
-
-import org.apache.commons.configuration.Configuration;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
-import org.apache.tinkerpop.gremlin.structure.Edge;
-import org.apache.tinkerpop.gremlin.structure.Graph;
-import org.apache.tinkerpop.gremlin.structure.Vertex;
-import org.apache.tinkerpop.gremlin.structure.VertexProperty;
-
-/**
- * @author Daniel Kuppitz (http://gremlin.guru)
- * @deprecated As of release 3.2.10, not directly replaced - consider graph provider specific bulk loading methods
- */
-@Deprecated
-public interface BulkLoader {
-
-    /**
-     * Gets or creates a clone of the given vertex in the given graph.
-     *
-     * @param vertex The vertex to be cloned.
-     * @param graph  The graph that holds the cloned vertex after this method was called.
-     * @param g      A standard traversal source for the given graph.
-     * @return The cloned vertex.
-     */
-    public Vertex getOrCreateVertex(final Vertex vertex, final Graph graph, final GraphTraversalSource g);
-
-    /**
-     * Creates a clone of the given edge between the given in- and out-vertices.
-     *
-     * @param edge      The edge to be cloned.
-     * @param outVertex The out-vertex in the given graph..
-     * @param inVertex  The in-vertex in the given graph.
-     * @param graph     The graph that holds the cloned edge after this method was called.
-     * @param g         A standard traversal source for the given graph.
-     * @return The cloned edge.
-     */
-    public default Edge createEdge(final Edge edge, final Vertex outVertex, final Vertex inVertex, final Graph graph, final GraphTraversalSource g) {
-        final Edge result = outVertex.addEdge(edge.label(), inVertex);
-        edge.properties().forEachRemaining(property -> result.property(property.key(), property.value()));
-        return result;
-    }
-
-    /**
-     * Gets or creates a clone of the given edge between the given in- and out-vertices.
-     *
-     * @param edge      The edge to be cloned.
-     * @param outVertex The out-vertex in the given graph..
-     * @param inVertex  The in-vertex in the given graph.
-     * @param graph     The graph that holds the cloned edge after this method was called.
-     * @param g         A standard traversal source for the given graph.
-     * @return The cloned edge.
-     */
-    public Edge getOrCreateEdge(final Edge edge, final Vertex outVertex, final Vertex inVertex, final Graph graph, final GraphTraversalSource g);
-
-    /**
-     * Creates a clone of the given property for the given vertex.
-     *
-     * @param property The property to be cloned.
-     * @param vertex   The vertex in the given graph..
-     * @param graph    The graph that holds the given vertex.
-     * @param g        A standard traversal source for the given graph.
-     * @return The cloned property.
-     */
-    public default VertexProperty createVertexProperty(final VertexProperty<?> property, final Vertex vertex, final Graph graph, final GraphTraversalSource g) {
-        final VertexProperty result = vertex.property(property.key(), property.value());
-        property.properties().forEachRemaining(metaProperty -> result.property(metaProperty.key(), metaProperty.value()));
-        return result;
-    }
-
-    /**
-     * Gets or creates a clone of the given property for the given vertex.
-     *
-     * @param property The property to be cloned.
-     * @param vertex   The vertex in the given graph..
-     * @param graph    The graph that holds the given vertex.
-     * @param g        A standard traversal source for the given graph.
-     * @return The cloned property.
-     */
-    public VertexProperty getOrCreateVertexProperty(final VertexProperty<?> property, final Vertex vertex, final Graph graph, final GraphTraversalSource g);
-
-    /**
-     * Get a vertex that matches the given vertex from the given graph.
-     *
-     * @param vertex The vertex to be matched.
-     * @param graph  The graph that holds the given vertex.
-     * @param g      A standard traversal source for the given graph.
-     * @return The matched vertex.
-     */
-    public Vertex getVertex(final Vertex vertex, final Graph graph, final GraphTraversalSource g);
-
-    /**
-     * Gets a vertex by its ID from the given graph.
-     *
-     * @param id    The vertex ID.
-     * @param graph The graph that holds the vertex with the given ID.
-     * @param g     A standard traversal source for the given graph.
-     * @return The vertex with the given ID.
-     */
-    public default Vertex getVertexById(final Object id, final Graph graph, final GraphTraversalSource g) {
-        return g.V().hasId(id).next();
-    }
-
-    /**
-     * @return Whether to use user supplied identifiers or not.
-     */
-    public boolean useUserSuppliedIds();
-
-    /**
-     * @return Whether to keep the original vertex identifiers in the target graph or not.
-     */
-    public boolean keepOriginalIds();
-
-    /**
-     * @return The name of the vertex property that is used to store the original vertex id.
-     */
-    public default String getVertexIdProperty() {
-        return BulkLoaderVertexProgram.DEFAULT_BULK_LOADER_VERTEX_ID;
-    }
-
-    /**
-     * Configures the BulkLoader instance.
-     *
-     * @param configuration The BulkLoader configuration.
-     */
-    public void configure(final Configuration configuration);
-}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/bulkloading/BulkLoaderVertexProgram.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/bulkloading/BulkLoaderVertexProgram.java
deleted file mode 100644
index 3570422..0000000
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/bulkloading/BulkLoaderVertexProgram.java
+++ /dev/null
@@ -1,499 +0,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.
- */
-package org.apache.tinkerpop.gremlin.process.computer.bulkloading;
-
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.ConfigurationException;
-import org.apache.commons.configuration.ConfigurationUtils;
-import org.apache.commons.configuration.PropertiesConfiguration;
-import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
-import org.apache.tinkerpop.gremlin.process.computer.Memory;
-import org.apache.tinkerpop.gremlin.process.computer.MessageScope;
-import org.apache.tinkerpop.gremlin.process.computer.Messenger;
-import org.apache.tinkerpop.gremlin.process.computer.VertexComputeKey;
-import org.apache.tinkerpop.gremlin.process.computer.VertexProgram;
-import org.apache.tinkerpop.gremlin.process.computer.util.AbstractVertexProgramBuilder;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.MutationListener;
-import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.EventStrategy;
-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.Property;
-import org.apache.tinkerpop.gremlin.structure.Vertex;
-import org.apache.tinkerpop.gremlin.structure.VertexProperty;
-import org.apache.tinkerpop.gremlin.structure.util.GraphFactory;
-import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
-import org.javatuples.Pair;
-import org.javatuples.Tuple;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * @author Daniel Kuppitz (http://gremlin.guru)
- * @deprecated As of release 3.2.10, not directly replaced - consider graph provider specific bulk loading methods
- */
-@Deprecated
-public class BulkLoaderVertexProgram implements VertexProgram<Tuple> {
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(BulkLoaderVertexProgram.class);
-
-    public static final String BULK_LOADER_VERTEX_PROGRAM_CFG_PREFIX = "gremlin.bulkLoaderVertexProgram";
-    public static final String BULK_LOADER_CLASS_CFG_KEY = String.join(".", BULK_LOADER_VERTEX_PROGRAM_CFG_PREFIX, "class");
-    public static final String BULK_LOADER_VERTEX_ID_CFG_KEY = String.join(".", BULK_LOADER_VERTEX_PROGRAM_CFG_PREFIX, "vertexIdProperty");
-    public static final String INTERMEDIATE_BATCH_SIZE_CFG_KEY = String.join(".", BULK_LOADER_VERTEX_PROGRAM_CFG_PREFIX, "intermediateBatchSize");
-    public static final String KEEP_ORIGINAL_IDS_CFG_KEY = String.join(".", BULK_LOADER_VERTEX_PROGRAM_CFG_PREFIX, "keepOriginalIds");
-    public static final String USER_SUPPLIED_IDS_CFG_KEY = String.join(".", BULK_LOADER_VERTEX_PROGRAM_CFG_PREFIX, "userSuppliedIds");
-    public static final String WRITE_GRAPH_CFG_KEY = String.join(".", BULK_LOADER_VERTEX_PROGRAM_CFG_PREFIX, "writeGraph");
-    public static final String DEFAULT_BULK_LOADER_VERTEX_ID = "bulkLoader.vertex.id";
-
-    private final MessageScope messageScope;
-    private final Set<VertexComputeKey> elementComputeKeys;
-    private Configuration configuration;
-    private BulkLoader bulkLoader;
-    private Graph graph;
-    private GraphTraversalSource g;
-    private long intermediateBatchSize;
-
-    private BulkLoadingListener listener;
-
-    private BulkLoaderVertexProgram() {
-        messageScope = MessageScope.Local.of(__::inE);
-        elementComputeKeys = new HashSet<>();
-    }
-
-    private BulkLoader createBulkLoader() {
-        final BulkLoader loader;
-        final Configuration config = configuration.subset(BULK_LOADER_VERTEX_PROGRAM_CFG_PREFIX);
-        if (config.containsKey("class")) {
-            final String className = config.getString("class");
-            try {
-                final Class<?> bulkLoaderClass = Class.forName(className);
-                loader = (BulkLoader) bulkLoaderClass.getConstructor().newInstance();
-            } catch (ClassNotFoundException e) {
-                LOGGER.error("Unable to find custom bulk loader class: {}", className);
-                throw new IllegalStateException(e);
-            } catch (Exception e) {
-                LOGGER.error("Unable to create an instance of the given bulk loader class: {}", className);
-                throw new IllegalStateException(e);
-            }
-        } else {
-            loader = new IncrementalBulkLoader();
-        }
-        loader.configure(configuration);
-        return loader;
-    }
-
-    /**
-     * Eventually commits the current transaction and closes the current graph instance. commit() will be called
-     * if close is set true, otherwise it will only be called if the intermediate batch size is set and reached.
-     *
-     * @param close Whether to close the current graph instance after calling commit() or not.
-     */
-    private void commit(final boolean close) {
-        if (!close && (intermediateBatchSize == 0L || listener.mutations() < intermediateBatchSize))
-            return;
-        if (null != graph) {
-            if (graph.features().graph().supportsTransactions()) {
-                LOGGER.info("Committing transaction on Graph instance: {} [{} mutations]", graph, listener.mutations());
-                try {
-                    graph.tx().commit();
-                    LOGGER.debug("Committed transaction on Graph instance: {}", graph);
-                    listener.resetCounter();
-                } catch (Exception e) {
-                    LOGGER.error("Failed to commit transaction on Graph instance: {}", graph);
-                    graph.tx().rollback();
-                    listener.resetCounter();
-                    throw e;
-                }
-            }
-            if (close) {
-                try {
-                    graph.close();
-                    LOGGER.info("Closed Graph instance: {}", graph);
-                    graph = null;
-                } catch (Exception e) {
-                    LOGGER.warn("Failed to close Graph instance", e);
-                }
-            }
-        }
-    }
-
-    @Override
-    public void setup(final Memory memory) {
-    }
-
-    @Override
-    public void loadState(final Graph graph, final Configuration config) {
-        configuration = new BaseConfiguration();
-        if (config != null) {
-            ConfigurationUtils.copy(config, configuration);
-        }
-        intermediateBatchSize = configuration.getLong(INTERMEDIATE_BATCH_SIZE_CFG_KEY, 0L);
-        elementComputeKeys.add(VertexComputeKey.of(DEFAULT_BULK_LOADER_VERTEX_ID, true));
-        bulkLoader = createBulkLoader();
-    }
-
-    @Override
-    public void storeState(final Configuration config) {
-        VertexProgram.super.storeState(config);
-        if (configuration != null) {
-            ConfigurationUtils.copy(configuration, config);
-        }
-    }
-
-    @Override
-    public void workerIterationStart(final Memory memory) {
-        if (null == graph) {
-            graph = GraphFactory.open(configuration.subset(WRITE_GRAPH_CFG_KEY));
-            LOGGER.info("Opened Graph instance: {}", graph);
-            try {
-                listener = new BulkLoadingListener();
-                g = graph.traversal().withStrategies(EventStrategy.build().addListener(listener).create());
-            } catch (Exception e) {
-                try {
-                    graph.close();
-                } catch (Exception e2) {
-                    LOGGER.warn("Failed to close Graph instance", e2);
-                }
-                throw e;
-            }
-        } else {
-            LOGGER.warn("Leaked Graph instance: {}", graph);
-        }
-    }
-
-    @Override
-    public void workerIterationEnd(final Memory memory) {
-        this.commit(true);
-    }
-
-    @Override
-    public void execute(final Vertex sourceVertex, final Messenger<Tuple> messenger, final Memory memory) {
-        try {
-            executeInternal(sourceVertex, messenger, memory);
-        } catch (Exception e) {
-            if (graph.features().graph().supportsTransactions()) {
-                graph.tx().rollback();
-            }
-            throw e;
-        }
-    }
-
-    private void executeInternal(final Vertex sourceVertex, final Messenger<Tuple> messenger, final Memory memory) {
-        if (memory.isInitialIteration()) {
-            this.listener.resetStats();
-            // get or create the vertex
-            final Vertex targetVertex = bulkLoader.getOrCreateVertex(sourceVertex, graph, g);
-            // write all the properties of the vertex to the newly created vertex
-            final Iterator<VertexProperty<Object>> vpi = sourceVertex.properties();
-            if (this.listener.isNewVertex()) {
-                vpi.forEachRemaining(vp -> bulkLoader.createVertexProperty(vp, targetVertex, graph, g));
-            } else {
-                vpi.forEachRemaining(vp -> bulkLoader.getOrCreateVertexProperty(vp, targetVertex, graph, g));
-            }
-            this.commit(false);
-            if (!bulkLoader.useUserSuppliedIds()) {
-                // create an id pair and send it to all the vertex's incoming adjacent vertices
-                sourceVertex.property(DEFAULT_BULK_LOADER_VERTEX_ID, targetVertex.id());
-                messenger.sendMessage(messageScope, Pair.with(sourceVertex.id(), targetVertex.id()));
-            }
-        } else if (memory.getIteration() == 1) {
-            if (bulkLoader.useUserSuppliedIds()) {
-                final Vertex outV = bulkLoader.getVertex(sourceVertex, graph, g);
-                final boolean incremental = outV.edges(Direction.OUT).hasNext();
-                sourceVertex.edges(Direction.OUT).forEachRemaining(edge -> {
-                    final Vertex inV = bulkLoader.getVertex(edge.inVertex(), graph, g);
-                    if (incremental) {
-                        bulkLoader.getOrCreateEdge(edge, outV, inV, graph, g);
-                    } else {
-                        bulkLoader.createEdge(edge, outV, inV, graph, g);
-                    }
-                    this.commit(false);
-                });
-            } else {
-                // create an id map and populate it with all the incoming messages
-                final Map<Object, Object> idPairs = new HashMap<>();
-                final Iterator<Tuple> idi = messenger.receiveMessages();
-                while (idi.hasNext()) {
-                    final Tuple idPair = idi.next();
-                    idPairs.put(idPair.getValue(0), idPair.getValue(1));
-                }
-                // get the vertex with given the dummy id property
-                final Object outVId = sourceVertex.value(DEFAULT_BULK_LOADER_VERTEX_ID);
-                final Vertex outV = bulkLoader.getVertexById(outVId, graph, g);
-                // for all the incoming edges of the vertex, get the incoming adjacent vertex and write the edge and its properties
-                sourceVertex.edges(Direction.OUT).forEachRemaining(edge -> {
-                    final Object inVId = idPairs.get(edge.inVertex().id());
-                    final Vertex inV = bulkLoader.getVertexById(inVId, graph, g);
-                    bulkLoader.getOrCreateEdge(edge, outV, inV, graph, g);
-                    this.commit(false);
-                });
-            }
-        } else if (memory.getIteration() == 2) {
-            final Object vertexId = sourceVertex.value(DEFAULT_BULK_LOADER_VERTEX_ID);
-            bulkLoader.getVertexById(vertexId, graph, g)
-                    .property(bulkLoader.getVertexIdProperty()).remove();
-            this.commit(false);
-        }
-    }
-
-    @Override
-    public boolean terminate(final Memory memory) {
-        switch (memory.getIteration()) {
-            case 1:
-                return bulkLoader.keepOriginalIds() || bulkLoader.getVertexIdProperty() == null;
-            case 2:
-                return true;
-        }
-        return false;
-    }
-
-    @Override
-    public Set<VertexComputeKey> getVertexComputeKeys() {
-        return elementComputeKeys;
-    }
-
-    @Override
-    public Set<MessageScope> getMessageScopes(final Memory memory) {
-        return Collections.singleton(messageScope);
-    }
-
-    @SuppressWarnings({"CloneDoesntDeclareCloneNotSupportedException", "CloneDoesntCallSuperClone"})
-    @Override
-    public VertexProgram<Tuple> clone() {
-        return this;
-    }
-
-    @Override
-    public GraphComputer.ResultGraph getPreferredResultGraph() {
-        return GraphComputer.ResultGraph.ORIGINAL;
-    }
-
-    @Override
-    public GraphComputer.Persist getPreferredPersist() {
-        return GraphComputer.Persist.NOTHING;
-    }
-
-    @Override
-    public String toString() {
-        final StringBuilder sb = new StringBuilder();
-        if (bulkLoader != null) {
-            sb.append("bulkLoader=").append(bulkLoader.getClass().getSimpleName()).append(", ");
-            sb.append("vertexIdProperty=").append(bulkLoader.getVertexIdProperty()).append(", ");
-            sb.append("userSuppliedIds=").append(bulkLoader.useUserSuppliedIds()).append(", ");
-            sb.append("keepOriginalIds=").append(bulkLoader.keepOriginalIds()).append(", ");
-        } else {
-            sb.append("bulkLoader=").append(bulkLoader).append(", ");
-        }
-        sb.append("batchSize=").append(intermediateBatchSize);
-        return StringFactory.vertexProgramString(this, sb.toString());
-    }
-
-    public static Builder build() {
-        return new Builder();
-    }
-
-    public static class Builder extends AbstractVertexProgramBuilder<Builder> {
-
-        private Builder() {
-            super(BulkLoaderVertexProgram.class);
-        }
-
-        @SuppressWarnings("unchecked")
-        @Override
-        public BulkLoaderVertexProgram create(final Graph graph) {
-            ConfigurationUtils.append(graph.configuration().subset(BULK_LOADER_VERTEX_PROGRAM_CFG_PREFIX), configuration);
-            return (BulkLoaderVertexProgram) VertexProgram.createVertexProgram(graph, configuration);
-        }
-
-        private void setGraphConfigurationProperty(final String key, final Object value) {
-            configuration.setProperty(String.join(".", WRITE_GRAPH_CFG_KEY, key), value);
-        }
-
-        /**
-         * Sets the class name of the BulkLoader implementation to be used.
-         */
-        public Builder bulkLoader(final String className) {
-            configuration.setProperty(BULK_LOADER_CLASS_CFG_KEY, className);
-            return this;
-        }
-
-        /**
-         * Sets the class of the BulkLoader implementation to be used.
-         */
-        public Builder bulkLoader(final Class<? extends BulkLoader> clazz) {
-            return bulkLoader(clazz.getCanonicalName());
-        }
-
-        /**
-         * Sets the name of the property that is used to store the original vertex identifiers in the target graph.
-         */
-        public Builder vertexIdProperty(final String name) {
-            configuration.setProperty(BULK_LOADER_VERTEX_ID_CFG_KEY, name);
-            return this;
-        }
-
-        /**
-         * Specifies whether user supplied identifiers should be used when the bulk loader creates vertices in the
-         * target graph.
-         */
-        public Builder userSuppliedIds(final boolean useUserSuppliedIds) {
-            configuration.setProperty(USER_SUPPLIED_IDS_CFG_KEY, useUserSuppliedIds);
-            return this;
-        }
-
-        /**
-         * Specifies whether the original vertex identifiers should be kept in the target graph or not. In case of false
-         * BulkLoaderVertexProgram will add another iteration to remove the properties and it won't be possible to use
-         * the data for further incremental bulk loads.
-         */
-        public Builder keepOriginalIds(final boolean keepOriginalIds) {
-            configuration.setProperty(KEEP_ORIGINAL_IDS_CFG_KEY, keepOriginalIds);
-            return this;
-        }
-
-        /**
-         * The batch size for a single transaction (number of vertices in the vertex loading stage; number of edges in
-         * the edge loading stage).
-         */
-        public Builder intermediateBatchSize(final int batchSize) {
-            configuration.setProperty(INTERMEDIATE_BATCH_SIZE_CFG_KEY, batchSize);
-            return this;
-        }
-
-        /**
-         * A configuration for the target graph that can be passed to GraphFactory.open().
-         */
-        public Builder writeGraph(final String configurationFile) throws ConfigurationException {
-            return writeGraph(new PropertiesConfiguration(configurationFile));
-        }
-
-        /**
-         * A configuration for the target graph that can be passed to GraphFactory.open().
-         */
-        public Builder writeGraph(final Configuration configuration) {
-            configuration.getKeys().forEachRemaining(key -> setGraphConfigurationProperty(key, configuration.getProperty(key)));
-            return this;
-        }
-    }
-
-    @Override
-    public Features getFeatures() {
-        return new Features() {
-            @Override
-            public boolean requiresLocalMessageScopes() {
-                return true;
-            }
-
-            @Override
-            public boolean requiresVertexPropertyAddition() {
-                return true;
-            }
-        };
-    }
-
-    static class BulkLoadingListener implements MutationListener {
-
-        private long counter;
-        private boolean isNewVertex;
-
-        public BulkLoadingListener() {
-            this.counter = 0L;
-            this.isNewVertex = false;
-        }
-
-        public boolean isNewVertex() {
-            return this.isNewVertex;
-        }
-
-        public long mutations() {
-            return this.counter;
-        }
-
-        public void resetStats() {
-            this.isNewVertex = false;
-        }
-
-        public void resetCounter() {
-            this.counter = 0L;
-        }
-
-        @Override
-        public void vertexAdded(final Vertex vertex) {
-            this.isNewVertex = true;
-            this.counter++;
-        }
-
-        @Override
-        public void vertexRemoved(final Vertex vertex) {
-            this.counter++;
-        }
-
-        @Override
-        public void vertexPropertyChanged(final Vertex element, final VertexProperty oldValue, final Object setValue,
-                                          final Object... vertexPropertyKeyValues) {
-            this.counter++;
-        }
-
-        @Override
-        public void vertexPropertyRemoved(final VertexProperty vertexProperty) {
-            this.counter++;
-        }
-
-        @Override
-        public void edgeAdded(final Edge edge) {
-            this.counter++;
-        }
-
-        @Override
-        public void edgeRemoved(final Edge edge) {
-            this.counter++;
-        }
-
-        @Override
-        public void edgePropertyChanged(final Edge element, final Property oldValue, final Object setValue) {
-            this.counter++;
-        }
-
-        @Override
-        public void edgePropertyRemoved(final Edge element, final Property property) {
-            this.counter++;
-        }
-
-        @Override
-        public void vertexPropertyPropertyChanged(final VertexProperty element, final Property oldValue, final Object setValue) {
-            this.counter++;
-        }
-
-        @Override
-        public void vertexPropertyPropertyRemoved(final VertexProperty element, final Property property) {
-            this.counter++;
-        }
-    }
-}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/bulkloading/IncrementalBulkLoader.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/bulkloading/IncrementalBulkLoader.java
deleted file mode 100644
index 5713773..0000000
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/bulkloading/IncrementalBulkLoader.java
+++ /dev/null
@@ -1,154 +0,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.
- */
-package org.apache.tinkerpop.gremlin.process.computer.bulkloading;
-
-import org.apache.commons.configuration.Configuration;
-import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
-import org.apache.tinkerpop.gremlin.structure.Edge;
-import org.apache.tinkerpop.gremlin.structure.Graph;
-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 java.util.Iterator;
-
-/**
- * @author Daniel Kuppitz (http://gremlin.guru)
- * @deprecated As of release 3.2.10, not directly replaced - consider graph provider specific bulk loading methods
- */
-@Deprecated
-public class IncrementalBulkLoader implements BulkLoader {
-
-    private String bulkLoaderVertexId = BulkLoaderVertexProgram.DEFAULT_BULK_LOADER_VERTEX_ID;
-    private boolean keepOriginalIds = true;
-    private boolean userSuppliedIds = false;
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Vertex getOrCreateVertex(final Vertex vertex, final Graph graph, final GraphTraversalSource g) {
-        final Iterator<Vertex> iterator = useUserSuppliedIds()
-                ? g.V().hasId(vertex.id())
-                : g.V().has(vertex.label(), bulkLoaderVertexId, vertex.id().toString());
-        return iterator.hasNext()
-                ? iterator.next()
-                : useUserSuppliedIds()
-                ? g.addV(vertex.label()).property(T.id, vertex.id()).next()
-                : g.addV(vertex.label()).property(bulkLoaderVertexId, vertex.id().toString()).next();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Edge getOrCreateEdge(final Edge edge, final Vertex outVertex, final Vertex inVertex, final Graph graph, final GraphTraversalSource g) {
-        final Edge e;
-        final Traversal<Vertex, Edge> t = g.V(outVertex).outE(edge.label()).filter(__.inV().is(inVertex));
-        if (t.hasNext()) {
-            e = t.next();
-            edge.properties().forEachRemaining(property -> {
-                final Property<?> existing = e.property(property.key());
-                if (!existing.isPresent() || !existing.value().equals(property.value())) {
-                    e.property(property.key(), property.value());
-                }
-            });
-        } else {
-            e = createEdge(edge, outVertex, inVertex, graph, g);
-        }
-        return e;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public VertexProperty getOrCreateVertexProperty(final VertexProperty<?> property, final Vertex vertex, final Graph graph, final GraphTraversalSource g) {
-        final VertexProperty<?> vp;
-        final VertexProperty<?> existing = vertex.property(property.key());
-        if (!existing.isPresent()) {
-            return createVertexProperty(property, vertex, graph, g);
-        }
-        if (!existing.value().equals(property.value())) {
-            vp = vertex.property(property.key(), property.value());
-        } else {
-            vp = existing;
-        }
-        property.properties().forEachRemaining(metaProperty -> {
-            final Property<?> existing2 = vp.property(metaProperty.key());
-            if (!existing2.isPresent() || !existing2.value().equals(metaProperty.value())) {
-                vp.property(metaProperty.key(), metaProperty.value());
-            }
-        });
-        return vp;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Vertex getVertex(final Vertex vertex, final Graph graph, final GraphTraversalSource g) {
-        return useUserSuppliedIds()
-                ? getVertexById(vertex.id(), graph, g)
-                : g.V().has(vertex.label(), bulkLoaderVertexId, vertex.id().toString()).next();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean useUserSuppliedIds() {
-        return userSuppliedIds;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean keepOriginalIds() {
-        return keepOriginalIds;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public String getVertexIdProperty() {
-        return bulkLoaderVertexId;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void configure(final Configuration configuration) {
-        if (configuration.containsKey(BulkLoaderVertexProgram.BULK_LOADER_VERTEX_ID_CFG_KEY)) {
-            bulkLoaderVertexId = configuration.getString(BulkLoaderVertexProgram.BULK_LOADER_VERTEX_ID_CFG_KEY);
-        }
-        if (configuration.containsKey(BulkLoaderVertexProgram.USER_SUPPLIED_IDS_CFG_KEY)) {
-            userSuppliedIds = configuration.getBoolean(BulkLoaderVertexProgram.USER_SUPPLIED_IDS_CFG_KEY);
-        }
-        if (configuration.containsKey(BulkLoaderVertexProgram.KEEP_ORIGINAL_IDS_CFG_KEY)) {
-            keepOriginalIds = configuration.getBoolean(BulkLoaderVertexProgram.KEEP_ORIGINAL_IDS_CFG_KEY);
-        }
-    }
-}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/bulkloading/OneTimeBulkLoader.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/bulkloading/OneTimeBulkLoader.java
deleted file mode 100644
index c918c7f..0000000
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/bulkloading/OneTimeBulkLoader.java
+++ /dev/null
@@ -1,109 +0,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.
- */
-package org.apache.tinkerpop.gremlin.process.computer.bulkloading;
-
-import org.apache.commons.configuration.Configuration;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
-import org.apache.tinkerpop.gremlin.structure.Edge;
-import org.apache.tinkerpop.gremlin.structure.Graph;
-import org.apache.tinkerpop.gremlin.structure.T;
-import org.apache.tinkerpop.gremlin.structure.Vertex;
-import org.apache.tinkerpop.gremlin.structure.VertexProperty;
-
-/**
- * {@link OneTimeBulkLoader} is a {@link BulkLoader} implementation that should be used for initial bulk loads. In
- * contrast to {@link IncrementalBulkLoader} it doesn't store temporary identifiers in the write graph nor does it
- * attempt to find existing elements, instead it  only clones each element from the source graph.
- *
- * @author Daniel Kuppitz (http://gremlin.guru)
- * @deprecated As of release 3.2.10, not directly replaced - consider graph provider specific bulk loading methods
- */
-@Deprecated
-public class OneTimeBulkLoader implements BulkLoader {
-
-    private boolean userSuppliedIds = false;
-
-    /**
-     * Creates a clone of the given vertex in the given graph.
-     */
-    @Override
-    public Vertex getOrCreateVertex(final Vertex vertex, final Graph graph, final GraphTraversalSource g) {
-        final GraphTraversal<Vertex, Vertex> t = g.addV(vertex.label());
-        return (useUserSuppliedIds() ? t.property(T.id, vertex.id()) : t).next();
-    }
-
-    /**
-     * Creates a clone of the given edge between the given in- and out-vertices.
-     */
-    @Override
-    public Edge getOrCreateEdge(final Edge edge, final Vertex outVertex, final Vertex inVertex, final Graph graph, final GraphTraversalSource g) {
-        return createEdge(edge, outVertex, inVertex, graph, g);
-    }
-
-    /**
-     * Creates a clone of the given property for the given vertex.
-     */
-    @Override
-    public VertexProperty getOrCreateVertexProperty(final VertexProperty<?> property, final Vertex vertex, final Graph graph, final GraphTraversalSource g) {
-        return createVertexProperty(property, vertex, graph, g);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Vertex getVertex(final Vertex vertex, final Graph graph, final GraphTraversalSource g) {
-        return getVertexById(vertex.id(), graph, g);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean useUserSuppliedIds() {
-        return userSuppliedIds;
-    }
-
-    /**
-     * Always returns false.
-     */
-    @Override
-    public boolean keepOriginalIds() {
-        return false;
-    }
-
-    /**
-     * Always returns null.
-     */
-    @Override
-    public String getVertexIdProperty() {
-        return null;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void configure(final Configuration configuration) {
-        if (configuration.containsKey(BulkLoaderVertexProgram.USER_SUPPLIED_IDS_CFG_KEY)) {
-            userSuppliedIds = configuration.getBoolean(BulkLoaderVertexProgram.USER_SUPPLIED_IDS_CFG_KEY);
-        }
-    }
-}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/clustering/connected/ConnectedComponentVertexProgram.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/clustering/connected/ConnectedComponentVertexProgram.java
index acc8f3c..ca81abf 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/clustering/connected/ConnectedComponentVertexProgram.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/clustering/connected/ConnectedComponentVertexProgram.java
@@ -18,9 +18,9 @@
  */
 package org.apache.tinkerpop.gremlin.process.computer.clustering.connected;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.ConfigurationUtils;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.configuration2.ConfigurationUtils;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
 import org.apache.tinkerpop.gremlin.process.computer.Memory;
 import org.apache.tinkerpop.gremlin.process.computer.MemoryComputeKey;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/clustering/peerpressure/ClusterCountMapReduce.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/clustering/peerpressure/ClusterCountMapReduce.java
index d343e8e..fcf15cb 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/clustering/peerpressure/ClusterCountMapReduce.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/clustering/peerpressure/ClusterCountMapReduce.java
@@ -25,7 +25,7 @@
 import org.apache.tinkerpop.gremlin.structure.Property;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 
 import java.io.Serializable;
 import java.util.HashSet;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/clustering/peerpressure/ClusterPopulationMapReduce.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/clustering/peerpressure/ClusterPopulationMapReduce.java
index 0318ad6..301fba1 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/clustering/peerpressure/ClusterPopulationMapReduce.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/clustering/peerpressure/ClusterPopulationMapReduce.java
@@ -24,7 +24,7 @@
 import org.apache.tinkerpop.gremlin.structure.Property;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 
 import java.io.Serializable;
 import java.util.HashMap;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/clustering/peerpressure/PeerPressureVertexProgram.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/clustering/peerpressure/PeerPressureVertexProgram.java
index b681807..2ead42e 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/clustering/peerpressure/PeerPressureVertexProgram.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/clustering/peerpressure/PeerPressureVertexProgram.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.process.computer.clustering.peerpressure;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
 import org.apache.tinkerpop.gremlin.process.computer.Memory;
 import org.apache.tinkerpop.gremlin.process.computer.MemoryComputeKey;
@@ -243,23 +243,6 @@
             PureTraversal.storeState(this.configuration, INITIAL_VOTE_STRENGTH_TRAVERSAL, initialVoteStrengthTraversal);
             return this;
         }
-
-        /**
-         * @deprecated As of release 3.2.0, replaced by {@link PeerPressureVertexProgram.Builder#edges(Traversal.Admin)}
-         */
-        @Deprecated
-        public Builder traversal(final TraversalSource traversalSource, final String scriptEngine, final String traversalScript, final Object... bindings) {
-            return this.edges(new ScriptTraversal<>(traversalSource, scriptEngine, traversalScript, bindings));
-        }
-
-        /**
-         * @deprecated As of release 3.2.0, replaced by {@link PeerPressureVertexProgram.Builder#edges(Traversal.Admin)}
-         */
-        @Deprecated
-        public Builder traversal(final Traversal.Admin<Vertex, Edge> edgeTraversal) {
-            return this.edges(edgeTraversal);
-        }
-
     }
 
     ////////////////////////////
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/ranking/pagerank/PageRankMapReduce.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/ranking/pagerank/PageRankMapReduce.java
index cff5e39..b2523b4 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/ranking/pagerank/PageRankMapReduce.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/ranking/pagerank/PageRankMapReduce.java
@@ -24,7 +24,7 @@
 import org.apache.tinkerpop.gremlin.structure.Property;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 
 import java.util.Iterator;
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/ranking/pagerank/PageRankVertexProgram.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/ranking/pagerank/PageRankVertexProgram.java
index ce0b5f2..247b1ea 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/ranking/pagerank/PageRankVertexProgram.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/ranking/pagerank/PageRankVertexProgram.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.process.computer.ranking.pagerank;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
 import org.apache.tinkerpop.gremlin.process.computer.Memory;
 import org.apache.tinkerpop.gremlin.process.computer.MemoryComputeKey;
@@ -257,31 +257,6 @@
             PureTraversal.storeState(this.configuration, INITIAL_RANK_TRAVERSAL, initialRankTraversal);
             return this;
         }
-
-        /**
-         * @deprecated As of release 3.2.0, replaced by {@link org.apache.tinkerpop.gremlin.process.computer.ranking.pagerank.PageRankVertexProgram.Builder#initialRank(Traversal.Admin)}
-         */
-        @Deprecated
-        public Builder vertexCount(final long vertexCount) {
-            this.configuration.setProperty(VERTEX_COUNT, (double) vertexCount);
-            return this;
-        }
-
-        /**
-         * @deprecated As of release 3.2.0, replaced by {@link org.apache.tinkerpop.gremlin.process.computer.ranking.pagerank.PageRankVertexProgram.Builder#edges(Traversal.Admin)}
-         */
-        @Deprecated
-        public Builder traversal(final TraversalSource traversalSource, final String scriptEngine, final String traversalScript, final Object... bindings) {
-            return this.edges(new ScriptTraversal<>(traversalSource, scriptEngine, traversalScript, bindings));
-        }
-
-        /**
-         * @deprecated As of release 3.2.0, replaced by {@link org.apache.tinkerpop.gremlin.process.computer.ranking.pagerank.PageRankVertexProgram.Builder#edges(Traversal.Admin)}
-         */
-        @Deprecated
-        public Builder traversal(final Traversal.Admin<Vertex, Edge> traversal) {
-            return this.edges(traversal);
-        }
     }
 
     ////////////////////////////
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/search/path/ShortestPathVertexProgram.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/search/path/ShortestPathVertexProgram.java
index 1949c53..88875b1 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/search/path/ShortestPathVertexProgram.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/search/path/ShortestPathVertexProgram.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.process.computer.search.path;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
 import org.apache.tinkerpop.gremlin.process.computer.Memory;
 import org.apache.tinkerpop.gremlin.process.computer.MemoryComputeKey;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/TraversalVertexProgram.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/TraversalVertexProgram.java
index eb56484..a5f9dfe 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/TraversalVertexProgram.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/TraversalVertexProgram.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.process.computer.traversal;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.process.computer.Computer;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
 import org.apache.tinkerpop.gremlin.process.computer.MapReduce;
@@ -178,7 +178,7 @@
                                 this.traversal.get().getParent().asStep().getNextStep().getNextStep() instanceof ComputerResultStep));
 
         // determine how to store halted traversers
-        final Iterator<?> itty = IteratorUtils.filter(this.traversal.get().getStrategies().toList(), strategy -> strategy instanceof HaltedTraverserStrategy).iterator();
+        final Iterator<?> itty = IteratorUtils.filter(this.traversal.get().getStrategies(), strategy -> strategy instanceof HaltedTraverserStrategy).iterator();
         this.haltedTraverserStrategy = itty.hasNext() ? (HaltedTraverserStrategy) itty.next() : HaltedTraverserStrategy.reference();
 
         // register traversal side-effects in memory
@@ -368,7 +368,7 @@
     public void workerIterationEnd(final Memory memory) {
         // store profile metrics in proper ProfileStep metrics
         if (this.profile) {
-            List<ProfileStep> profileSteps = TraversalHelper.getStepsOfAssignableClassRecursively(ProfileStep.class, this.traversal.get());
+            final List<ProfileStep> profileSteps = TraversalHelper.getStepsOfAssignableClassRecursively(ProfileStep.class, this.traversal.get());
             // guess the profile step to store data
             int profileStepIndex = memory.getIteration();
             // if we guess wrongly write timing into last step
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/PageRankVertexProgramStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/PageRankVertexProgramStep.java
index 277b4c6..c265927 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/PageRankVertexProgramStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/PageRankVertexProgramStep.java
@@ -27,8 +27,6 @@
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
-import org.apache.tinkerpop.gremlin.process.traversal.step.ByModulating;
-import org.apache.tinkerpop.gremlin.process.traversal.step.TimesModulating;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.Parameters;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
@@ -46,8 +44,7 @@
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
-public final class PageRankVertexProgramStep extends VertexProgramStep
-        implements TraversalParent, ByModulating, TimesModulating, Configuring {
+public final class PageRankVertexProgramStep extends VertexProgramStep implements TraversalParent, Configuring {
 
     private Parameters parameters = new Parameters();
     private PureTraversal<Vertex, Edge> edgeTraversal;
@@ -76,7 +73,7 @@
             if (!(keyValues[1] instanceof Integer))
                 throw new IllegalArgumentException("PageRank.times requires an Integer as its argument");
             this.times = (int) keyValues[1];
-        }else {
+        } else {
             this.parameters.set(this, keyValues);
         }
     }
@@ -86,33 +83,6 @@
         return parameters;
     }
 
-    /**
-     * @deprecated As of release 3.4.0, replaced by {@link #configure(Object...)}
-     */
-    @Deprecated
-    @Override
-    public void modulateBy(final Traversal.Admin<?, ?> edgeTraversal) {
-        configure(PageRank.edges, edgeTraversal);
-    }
-
-    /**
-     * @deprecated As of release 3.4.0, replaced by {@link #configure(Object...)}
-     */
-    @Deprecated
-    @Override
-    public void modulateBy(final String pageRankProperty) {
-        configure(PageRank.propertyName, pageRankProperty);
-    }
-
-    /**
-     * @deprecated As of release 3.4.0, replaced by {@link #configure(Object...)}
-     */
-    @Deprecated
-    @Override
-    public void modulateTimes(int times) {
-        configure(PageRank.times, times);
-    }
-
     @Override
     public List<Traversal.Admin<Vertex, Edge>> getLocalChildren() {
         return Collections.singletonList(this.edgeTraversal.get());
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/PeerPressureVertexProgramStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/PeerPressureVertexProgramStep.java
index e1cba60..d98cf5e 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/PeerPressureVertexProgramStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/PeerPressureVertexProgramStep.java
@@ -26,9 +26,7 @@
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
-import org.apache.tinkerpop.gremlin.process.traversal.step.ByModulating;
 import org.apache.tinkerpop.gremlin.process.traversal.step.Configuring;
-import org.apache.tinkerpop.gremlin.process.traversal.step.TimesModulating;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.Parameters;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
@@ -46,8 +44,7 @@
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
-public final class PeerPressureVertexProgramStep extends VertexProgramStep
-        implements TraversalParent, ByModulating, TimesModulating, Configuring {
+public final class PeerPressureVertexProgramStep extends VertexProgramStep implements TraversalParent, Configuring {
 
     private Parameters parameters = new Parameters();
     private PureTraversal<Vertex, Edge> edgeTraversal;
@@ -89,33 +86,6 @@
         return super.hashCode() ^ this.edgeTraversal.hashCode() ^ this.clusterProperty.hashCode() ^ this.times;
     }
 
-    /**
-     * @deprecated As of release 3.4.0, replaced by {@link #configure(Object...)}
-     */
-    @Deprecated
-    @Override
-    public void modulateBy(final Traversal.Admin<?, ?> edgeTraversal) {
-        configure(PeerPressure.edges, edgeTraversal);
-    }
-
-    /**
-     * @deprecated As of release 3.4.0, replaced by {@link #configure(Object...)}
-     */
-    @Deprecated
-    @Override
-    public void modulateBy(final String clusterProperty) {
-        configure(PeerPressure.propertyName, clusterProperty);
-    }
-
-    /**
-     * @deprecated As of release 3.4.0, replaced by {@link #configure(Object...)}
-     */
-    @Deprecated
-    @Override
-    public void modulateTimes(int times) {
-        configure(PeerPressure.times, times);
-    }
-
     @Override
     public List<Traversal.Admin<Vertex, Edge>> getLocalChildren() {
         return Collections.singletonList(this.edgeTraversal.get());
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/ProgramVertexProgramStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/ProgramVertexProgramStep.java
index 49add72..025069e 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/ProgramVertexProgramStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/ProgramVertexProgramStep.java
@@ -19,7 +19,7 @@
 
 package org.apache.tinkerpop.gremlin.process.computer.traversal.step.map;
 
-import org.apache.commons.configuration.MapConfiguration;
+import org.apache.commons.configuration2.MapConfiguration;
 import org.apache.tinkerpop.gremlin.process.computer.GraphFilter;
 import org.apache.tinkerpop.gremlin.process.computer.Memory;
 import org.apache.tinkerpop.gremlin.process.computer.VertexProgram;
@@ -48,7 +48,6 @@
         super(traversal);
         this.configuration = new HashMap<>();
         final MapConfiguration base = new MapConfiguration(this.configuration);
-        base.setDelimiterParsingDisabled(true);
         vertexProgram.storeState(base);
         this.toStringOfVertexProgram = vertexProgram.toString();
         this.traverserRequirements = vertexProgram.getTraverserRequirements();
@@ -57,7 +56,6 @@
     @Override
     public VertexProgram generateProgram(final Graph graph, final Memory memory) {
         final MapConfiguration base = new MapConfiguration(this.configuration);
-        base.setDelimiterParsingDisabled(true);
         PureTraversal.storeState(base, ROOT_TRAVERSAL, TraversalHelper.getRootTraversal(this.getTraversal()).clone());
         base.setProperty(STEP_ID, this.getId());
         if (memory.exists(TraversalVertexProgram.HALTED_TRAVERSERS))
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/TraversalVertexProgramStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/TraversalVertexProgramStep.java
index 30cfee5..3fa36a9 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/TraversalVertexProgramStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/TraversalVertexProgramStep.java
@@ -74,7 +74,7 @@
         final Traversal.Admin<?, ?> computerSpecificTraversal = this.computerTraversal.getPure();
         final TraversalStrategies computerSpecificStrategies = this.getTraversal().getStrategies().clone();
 
-        IteratorUtils.filter(TraversalStrategies.GlobalCache.getStrategies(graph.getClass()).toList(),
+        IteratorUtils.filter(TraversalStrategies.GlobalCache.getStrategies(graph.getClass()),
                 s -> s instanceof TraversalStrategy.ProviderOptimizationStrategy).forEach(computerSpecificStrategies::addStrategies);
 
         computerSpecificTraversal.setStrategies(computerSpecificStrategies);
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/decoration/VertexProgramStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/decoration/VertexProgramStrategy.java
index fa6e23f..8c2e28a 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/decoration/VertexProgramStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/decoration/VertexProgramStrategy.java
@@ -19,8 +19,8 @@
 
 package org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration;
 
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.MapConfiguration;
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.configuration2.MapConfiguration;
 import org.apache.tinkerpop.gremlin.process.computer.Computer;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
 import org.apache.tinkerpop.gremlin.process.computer.traversal.step.VertexComputing;
@@ -34,7 +34,7 @@
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
-import org.apache.tinkerpop.gremlin.process.traversal.step.ReadWriting;
+import org.apache.tinkerpop.gremlin.process.traversal.lambda.AbstractLambdaTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.GraphStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.EmptyStep;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
@@ -71,7 +71,9 @@
     @Override
     public void apply(final Traversal.Admin<?, ?> traversal) {
         // VertexPrograms can only execute at the root level of a Traversal and should not be applied locally prior to RemoteStrategy
-        if (!(traversal.getParent() instanceof EmptyStep) || traversal.getStrategies().getStrategy(RemoteStrategy.class).isPresent())
+        if (!(traversal.isRoot())
+                || traversal instanceof AbstractLambdaTraversal
+                || traversal.getStrategies().getStrategy(RemoteStrategy.class).isPresent())
             return;
 
         // back propagate as()-labels off of vertex computing steps
@@ -160,8 +162,8 @@
     }
 
     public static Optional<Computer> getComputer(final TraversalStrategies strategies) {
-        final Optional<TraversalStrategy<?>> optional = strategies.toList().stream().filter(strategy -> strategy instanceof VertexProgramStrategy).findAny();
-        return optional.isPresent() ? Optional.of(((VertexProgramStrategy) optional.get()).computer) : Optional.empty();
+        final Optional<VertexProgramStrategy> optional = strategies.getStrategy(VertexProgramStrategy.class);
+        return optional.isPresent() ? Optional.of(optional.get().computer) : Optional.empty();
     }
 
     public void addGraphComputerStrategies(final TraversalSource traversalSource) {
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/optimization/MessagePassingReductionStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/optimization/MessagePassingReductionStrategy.java
index cff152e..f32d376 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/optimization/MessagePassingReductionStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/optimization/MessagePassingReductionStrategy.java
@@ -40,6 +40,7 @@
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.TraversalMapStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.VertexStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.IdentityStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.ProfileSideEffectStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.SideEffectStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.EmptyStep;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
@@ -98,7 +99,26 @@
                         !(computerTraversal.getStartStep().getNextStep() instanceof Barrier) &&
                         TraversalHelper.hasStepOfAssignableClassRecursively(Arrays.asList(VertexStep.class, EdgeVertexStep.class), computerTraversal) &&
                         TraversalHelper.isLocalStarGraph(computerTraversal)) {
-                    final Step barrier = (Step) TraversalHelper.getFirstStepOfAssignableClass(Barrier.class, computerTraversal).orElse(null);
+                    Step barrier = (Step) TraversalHelper.getFirstStepOfAssignableClass(Barrier.class, computerTraversal).orElse(null);
+
+                    // if the barrier isn't present gotta check for uncapped profile() which can happen if you do
+                    // profile("metrics") - see below for more worries
+                    if (null == barrier) {
+                        final ProfileSideEffectStep pses = TraversalHelper.getFirstStepOfAssignableClass(ProfileSideEffectStep.class, computerTraversal).orElse(null);
+                        if (pses != null)
+                            barrier = pses.getPreviousStep();
+                    }
+
+                    // if the barrier is a profile() then we'll mess stuff up if we wrap that in a local() as in:
+                    //    local(..., ProfileSideEffectStep)
+                    // which won't compute right on OLAP (or anything??). By stepping back we cut things off at
+                    // just before the ProfileSideEffectStep to go inside the local() so that ProfileSideEffectStep
+                    // shows up just after it
+                    //
+                    // why does this strategy need to know so much about profile!?!
+                    if (barrier != null && barrier.getPreviousStep() instanceof ProfileSideEffectStep)
+                        barrier = barrier.getPreviousStep().getPreviousStep();
+
                     if (MessagePassingReductionStrategy.insertElementId(barrier)) // out().count() -> out().id().count()
                         TraversalHelper.insertBeforeStep(new IdStep(computerTraversal), barrier, computerTraversal);
                     if (!(MessagePassingReductionStrategy.endsWithElement(null == barrier ? computerTraversal.getEndStep() : barrier))) {
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/verification/VertexProgramRestrictionStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/verification/VertexProgramRestrictionStrategy.java
new file mode 100644
index 0000000..5c9d4b2
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/verification/VertexProgramRestrictionStrategy.java
@@ -0,0 +1,58 @@
+/*
+ * 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.computer.traversal.strategy.verification;
+
+import org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ComputerVerificationStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.VerificationException;
+
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * Detects the presence of a {@link VertexProgramStrategy} and throws an {@link IllegalStateException} if it is found.
+ *
+ * @author Marc de Lignie
+ */
+public final class VertexProgramRestrictionStrategy extends AbstractTraversalStrategy<TraversalStrategy.VerificationStrategy> implements TraversalStrategy.VerificationStrategy {
+
+    private static final VertexProgramRestrictionStrategy INSTANCE = new VertexProgramRestrictionStrategy();
+
+    private VertexProgramRestrictionStrategy() {
+    }
+
+    @Override
+    public void apply(final Traversal.Admin<?, ?> traversal) {
+        if (traversal.getStrategies().toList().contains(VertexProgramStrategy.instance())) {
+            throw new VerificationException("The TraversalSource does not allow the use of a GraphComputer", traversal);
+        }
+    }
+
+    @Override
+    public Set<Class<? extends VerificationStrategy>> applyPost() {
+        return Collections.singleton(ComputerVerificationStrategy.class);
+    }
+
+    public static VertexProgramRestrictionStrategy instance() {
+        return INSTANCE;
+    }
+}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/util/AbstractVertexProgramBuilder.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/util/AbstractVertexProgramBuilder.java
index 3d8cedc..680dd79 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/util/AbstractVertexProgramBuilder.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/util/AbstractVertexProgramBuilder.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.process.computer.util;
 
-import org.apache.commons.configuration.BaseConfiguration;
+import org.apache.commons.configuration2.BaseConfiguration;
 import org.apache.tinkerpop.gremlin.process.computer.VertexProgram;
 import org.apache.tinkerpop.gremlin.structure.Graph;
 
@@ -29,21 +29,10 @@
 
     protected final BaseConfiguration configuration = new BaseConfiguration();
 
-    public AbstractVertexProgramBuilder() {
-        this.configuration.setDelimiterParsingDisabled(true);
-    }
-
     public AbstractVertexProgramBuilder(final Class<? extends VertexProgram> vertexProgramClass) {
-        this();
         this.configuration.setProperty(VertexProgram.VERTEX_PROGRAM, vertexProgramClass.getName());
     }
 
-    /*@Override
-    public B graph(final Graph graph) {
-        this.configuration.setProperty(Graph.GRAPH, graph.getClass().getName());
-        return (B) this;
-    }*/
-
     /**
      * {@inheritDoc}
      */
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/util/ComputerGraph.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/util/ComputerGraph.java
index 2e4082c..77453fe 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/util/ComputerGraph.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/util/ComputerGraph.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.process.computer.util;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
 import org.apache.tinkerpop.gremlin.process.computer.VertexComputeKey;
 import org.apache.tinkerpop.gremlin.process.computer.VertexProgram;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/util/StaticMapReduce.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/util/StaticMapReduce.java
index ee90a53..30f2590 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/util/StaticMapReduce.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/util/StaticMapReduce.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.process.computer.util;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.process.computer.MapReduce;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/util/StaticVertexProgram.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/util/StaticVertexProgram.java
index 87f975d..b4d097a 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/util/StaticVertexProgram.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/util/StaticVertexProgram.java
@@ -19,7 +19,7 @@
 package org.apache.tinkerpop.gremlin.process.computer.util;
 
 import org.apache.tinkerpop.gremlin.process.computer.VertexProgram;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/util/VertexProgramHelper.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/util/VertexProgramHelper.java
index 2297c90..ef497ff 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/util/VertexProgramHelper.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/util/VertexProgramHelper.java
@@ -18,8 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.process.computer.util;
 
-import org.apache.commons.configuration.AbstractConfiguration;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.AbstractConfiguration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.process.computer.VertexComputeKey;
 import org.apache.tinkerpop.gremlin.process.traversal.Step;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
@@ -61,8 +61,6 @@
     }
 
     public static void serialize(final Object object, final Configuration configuration, final String key) {
-        if (configuration instanceof AbstractConfiguration)
-            ((AbstractConfiguration) configuration).setDelimiterParsingDisabled(true);
         try {
             configuration.setProperty(key, Base64.getEncoder().encodeToString(Serializer.serializeObject(object)));
         } catch (final IOException e) {
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/RemoteConnection.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/RemoteConnection.java
index 0c124e7..639e286 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/RemoteConnection.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/RemoteConnection.java
@@ -18,10 +18,11 @@
  */
 package org.apache.tinkerpop.gremlin.process.remote;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.process.remote.traversal.RemoteTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.structure.Transaction;
 
 import java.lang.reflect.Constructor;
 import java.util.Iterator;
@@ -41,6 +42,13 @@
     public static final String GREMLIN_REMOTE_CONNECTION_CLASS = GREMLIN_REMOTE + "remoteConnectionClass";
 
     /**
+     * Creates a {@link Transaction} object designed to work with remote semantics.
+     */
+    public default Transaction tx() {
+        throw new UnsupportedOperationException("This implementation does not support remote transactions");
+    }
+
+    /**
      * Submits {@link Traversal} {@link Bytecode} to a server and returns a promise of a {@link RemoteTraversal}.
      * The {@link RemoteTraversal} is an abstraction over two types of results that can be returned as part of the
      * response from the server: the results of the {@link Traversal} itself and the side-effects that it produced.
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/AbstractRemoteTraversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/AbstractRemoteTraversal.java
index b233a31..363de6e 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/AbstractRemoteTraversal.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/AbstractRemoteTraversal.java
@@ -53,6 +53,11 @@
     public abstract Traverser.Admin<E> nextTraverser();
 
     @Override
+    public TraversalSideEffects getSideEffects() {
+        throw new UnsupportedOperationException("Remote traversals do not support this method");
+    }
+
+    @Override
     public Bytecode getBytecode() {
         throw new UnsupportedOperationException("Remote traversals do not support this method");
     }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/AbstractRemoteTraversalSideEffects.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/AbstractRemoteTraversalSideEffects.java
deleted file mode 100644
index 3456848..0000000
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/AbstractRemoteTraversalSideEffects.java
+++ /dev/null
@@ -1,103 +0,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.
- */
-package org.apache.tinkerpop.gremlin.process.remote.traversal;
-
-import org.apache.tinkerpop.gremlin.process.traversal.TraversalSideEffects;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
-import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
-
-import java.util.Optional;
-import java.util.function.BinaryOperator;
-import java.util.function.Supplier;
-import java.util.function.UnaryOperator;
-
-/**
- * @author Stephen Mallette (http://stephen.genoprime.com)
- * @deprecated As of release 3.3.8, not directly replaced, prefer use of {@link GraphTraversal#cap(String, String...)}
- * to return the result as part of the traversal iteration.
- */
-@Deprecated
-public abstract class AbstractRemoteTraversalSideEffects implements RemoteTraversalSideEffects {
-
-    @Override
-    public void set(final String key, final Object value) throws IllegalArgumentException {
-        throw new UnsupportedOperationException("Remote traversals do not support this method");
-    }
-
-    @Override
-    public void remove(final String key) {
-        throw new UnsupportedOperationException("Remote traversals do not support this method");
-    }
-
-    @Override
-    public <V> void register(final String key, final Supplier<V> initialValue, BinaryOperator<V> reducer) {
-        throw new UnsupportedOperationException("Remote traversals do not support this method");
-    }
-
-    @Override
-    public <V> void registerIfAbsent(final String key, final Supplier<V> initialValue, BinaryOperator<V> reducer) {
-        throw new UnsupportedOperationException("Remote traversals do not support this method");
-    }
-
-    @Override
-    public <V> BinaryOperator<V> getReducer(final String key) throws IllegalArgumentException {
-        throw new UnsupportedOperationException("Remote traversals do not support this method");
-    }
-
-    @Override
-    public <V> Supplier<V> getSupplier(final String key) throws IllegalArgumentException {
-        throw new UnsupportedOperationException("Remote traversals do not support this method");
-    }
-
-    @Override
-    public void add(final String key, final Object value) throws IllegalArgumentException {
-        throw new UnsupportedOperationException("Remote traversals do not support this method");
-    }
-
-    @Override
-    public <S> void setSack(final Supplier<S> initialValue, UnaryOperator<S> splitOperator, final BinaryOperator<S> mergeOperator) {
-        throw new UnsupportedOperationException("Remote traversals do not support this method");
-    }
-
-    @Override
-    public <S> Supplier<S> getSackInitialValue() {
-        return null;
-        // throw new UnsupportedOperationException("Remote traversals do not support this method");
-    }
-
-    @Override
-    public <S> UnaryOperator<S> getSackSplitter() {
-        throw new UnsupportedOperationException("Remote traversals do not support this method");
-    }
-
-    @Override
-    public <S> BinaryOperator<S> getSackMerger() {
-        throw new UnsupportedOperationException("Remote traversals do not support this method");
-    }
-
-    @Override
-    public TraversalSideEffects clone() {
-        throw new UnsupportedOperationException("Remote traversals do not support this method");
-    }
-
-    @Override
-    public void mergeInto(final TraversalSideEffects sideEffects) {
-        throw new UnsupportedOperationException("Remote traversals do not support this method");
-    }
-}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/EmbeddedRemoteTraversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/EmbeddedRemoteTraversal.java
index 10e27ae..9dc37e7 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/EmbeddedRemoteTraversal.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/EmbeddedRemoteTraversal.java
@@ -39,15 +39,6 @@
         return t.asAdmin().nextTraverser();
     }
 
-    /**
-     * @deprecated as of release 3.3.8, not directly replaced, see {@link Admin#getSideEffects()} for more information.
-     */
-    @Override
-    @Deprecated
-    public RemoteTraversalSideEffects getSideEffects() {
-        return new EmbeddedRemoteTraversalSideEffects(t.asAdmin().getSideEffects());
-    }
-
     @Override
     public boolean hasNext() {
         return t.hasNext();
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/EmbeddedRemoteTraversalSideEffects.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/EmbeddedRemoteTraversalSideEffects.java
deleted file mode 100644
index 06815fd..0000000
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/EmbeddedRemoteTraversalSideEffects.java
+++ /dev/null
@@ -1,51 +0,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.
- */
-package org.apache.tinkerpop.gremlin.process.remote.traversal;
-
-import org.apache.tinkerpop.gremlin.process.traversal.TraversalSideEffects;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
-
-import java.util.Set;
-
-/**
- * Generated by the {@link EmbeddedRemoteTraversal} to help simulate a remote traversal side-effects within the same JVM.
- *
- * @author Stephen Mallette (http://stephen.genoprime.com)
- * @deprecated As of release 3.3.8, not directly replaced, prefer use of {@link GraphTraversal#cap(String, String...)}
- * to return the result as part of the traversal iteration.
- */
-@Deprecated
-public class EmbeddedRemoteTraversalSideEffects extends AbstractRemoteTraversalSideEffects {
-
-    private final TraversalSideEffects sideEffects;
-
-    public EmbeddedRemoteTraversalSideEffects(final TraversalSideEffects sideEffects) {
-        this.sideEffects = sideEffects;
-    }
-
-    @Override
-    public <V> V get(final String key) throws IllegalArgumentException {
-        return sideEffects.get(key);
-    }
-
-    @Override
-    public Set<String> keys() {
-        return sideEffects.keys();
-    }
-}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/RemoteTraversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/RemoteTraversal.java
index ed4b1eb..69db6c5 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/RemoteTraversal.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/RemoteTraversal.java
@@ -37,14 +37,4 @@
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
 public interface RemoteTraversal<S,E> extends Traversal.Admin<S,E> {
-
-    /**
-     * Returns remote side-effects generated by the traversal so that they can be accessible to the client. Note that
-     * "side-effect" refers to the value in "a" in the traversal {@code g.V().aggregate('a').values('name')}.
-     *
-     * @deprecated as of release 3.3.8, not directly replaced, see {@link Admin#getSideEffects()} for more information.
-     */
-    @Override
-    @Deprecated
-    public RemoteTraversalSideEffects getSideEffects();
 }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/RemoteTraversalSideEffects.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/RemoteTraversalSideEffects.java
deleted file mode 100644
index 0d1a510..0000000
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/RemoteTraversalSideEffects.java
+++ /dev/null
@@ -1,48 +0,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.
- */
-package org.apache.tinkerpop.gremlin.process.remote.traversal;
-
-import org.apache.tinkerpop.gremlin.process.traversal.TraversalSideEffects;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
-import org.apache.tinkerpop.gremlin.process.traversal.util.DefaultTraversalSideEffects;
-
-/**
- * When a traversal is executed remotely, the ability to retrieve those side-effects (i.e. the value in "a" in the
- * traversal {@code g.V().aggregate('a').values('name')}) can be exposed through this interface. As an example,
- * with TinkerPop's {@code DriverRemoteConnection} that connects to Gremlin Server as a "remote", the side-effects
- * are left on the server. The {@code RemoteTraversalSideEffects} implementation, in that case, lazily loads those
- * side-effects when requested. Implementations should attempt to match the features of the locally processed
- * {@link DefaultTraversalSideEffects} to keep consistency.
- *
- * @author Stephen Mallette (http://stephen.genoprime.com)
- * @deprecated As of release 3.3.8, not directly replaced, prefer use of {@link GraphTraversal#cap(String, String...)}
- * to return the result as part of the traversal iteration.
- */
-@Deprecated
-public interface RemoteTraversalSideEffects extends TraversalSideEffects, AutoCloseable {
-
-    /**
-     * If the "remote" that actually executed the traversal maintained resources that can be released, when the user
-     * is done with the side-effects, then this method can be used to trigger that release.
-     */
-    @Override
-    public default void close() throws Exception {
-        //  do nothing
-    }
-}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/step/map/RemoteStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/step/map/RemoteStep.java
index a103f6a..be623cd 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/step/map/RemoteStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/step/map/RemoteStep.java
@@ -88,7 +88,6 @@
             if (null == traversalFuture.get()) {
                 traversalFuture.set(this.remoteConnection.submitAsync(this.traversal.getBytecode()).<Traversal<?, E>>thenApply(t -> {
                     this.remoteTraversal = (RemoteTraversal<?, E>) t;
-                    this.traversal.setSideEffects(this.remoteTraversal.getSideEffects());
                     return traversal;
                 }));
             }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/strategy/decoration/RemoteStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/strategy/decoration/RemoteStrategy.java
index 79855d0..fcd514e 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/strategy/decoration/RemoteStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/strategy/decoration/RemoteStrategy.java
@@ -82,7 +82,7 @@
 
     @Override
     public void apply(final Traversal.Admin<?, ?> traversal) {
-        if (!(traversal.getParent() instanceof EmptyStep))
+        if (!(traversal.isRoot()))
             return;
 
         // remote step wraps the traversal and emits the results from the remote connection.
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/AnonymousTraversalSource.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/AnonymousTraversalSource.java
index 186ee86..46a75b2 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/AnonymousTraversalSource.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/AnonymousTraversalSource.java
@@ -18,8 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal;
 
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.configuration2.builder.fluent.Configurations;
 import org.apache.tinkerpop.gremlin.process.remote.RemoteConnection;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
 import org.apache.tinkerpop.gremlin.structure.Graph;
@@ -62,7 +62,8 @@
      * @param configFile a path to a file that would normally be provided to configure a {@link RemoteConnection}
      */
     public T withRemote(final String configFile) throws Exception {
-        return withRemote(new PropertiesConfiguration(configFile));
+        final Configurations configs = new Configurations();
+        return withRemote(configs.properties((configFile)));
     }
 
     /**
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Bytecode.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Bytecode.java
index ccc35dd..56422c7 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Bytecode.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Bytecode.java
@@ -54,6 +54,12 @@
     private List<Instruction> sourceInstructions = new ArrayList<>();
     private List<Instruction> stepInstructions = new ArrayList<>();
 
+    public Bytecode() {}
+
+    Bytecode(final String sourceName, final Object... arguments) {
+        this.sourceInstructions.add(new Instruction(sourceName, flattenArguments(arguments)));
+    }
+
     /**
      * Add a {@link TraversalSource} instruction to the bytecode.
      *
@@ -136,6 +142,10 @@
         return bindingsMap;
     }
 
+    public boolean isEmpty() {
+        return this.sourceInstructions.isEmpty() && this.stepInstructions.isEmpty();
+    }
+
     private static final void addArgumentBinding(final Map<String, Object> bindingsMap, final Object argument) {
         if (argument instanceof Binding)
             bindingsMap.put(((Binding) argument).key, ((Binding) argument).value);
@@ -286,9 +296,14 @@
                 return new Binding<>(variable, convertArgument(argument, false));
         }
         //
-        if (argument instanceof Traversal)
+        if (argument instanceof Traversal) {
+            // prevent use of "g" to spawn child traversals
+            if (((Traversal) argument).asAdmin().getTraversalSource().isPresent())
+                throw new IllegalStateException(String.format(
+                        "The child traversal of %s was not spawned anonymously - use the __ class rather than a TraversalSource to construct the child traversal", argument));
+
             return ((Traversal) argument).asAdmin().getBytecode();
-        else if (argument instanceof Map) {
+        } else if (argument instanceof Map) {
             final Map<Object, Object> map = new LinkedHashMap<>(((Map) argument).size());
             for (final Map.Entry<?, ?> entry : ((Map<?, ?>) argument).entrySet()) {
                 map.put(convertArgument(entry.getKey(), true), convertArgument(entry.getValue(), true));
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GraphOp.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GraphOp.java
new file mode 100644
index 0000000..370009c
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GraphOp.java
@@ -0,0 +1,56 @@
+/*
+ * 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;
+
+/**
+ * A {@code GraphOp} or "graph operation" is a static {@link Bytecode} form that does not translate to a traversal
+ * but instead refers to a specific function to perform on a graph instance.
+ */
+public enum GraphOp {
+
+    /**
+     * Commit a transaction.
+     */
+    TX_COMMIT(new Bytecode("tx", "commit")),
+
+    /**
+     * Rollback a transaction.
+     */
+    TX_ROLLBACK(new Bytecode("tx", "rollback"));
+
+    private final Bytecode bytecode;
+
+    GraphOp(final Bytecode bc) {
+        this.bytecode = bc;
+    }
+
+    /**
+     * Gets the {@link Bytecode} that represents this graph operation. There is no notion of immutable bytecode
+     * instances so it is important that the object returned here is not modified. If they are changed, the operations
+     * will no longer be recognized. In a future version, we should probably introduce the concept of immutable
+     * bytecode to prevent this possibility - https://issues.apache.org/jira/browse/TINKERPOP-2545
+     */
+    public Bytecode getBytecode() {
+        return bytecode;
+    }
+
+    public boolean equals(final Bytecode bc) {
+        return bytecode.equals(bc);
+    }
+}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Order.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Order.java
index 2b50a0c..d4d55b0 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Order.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Order.java
@@ -32,52 +32,16 @@
 public enum Order implements Comparator<Object> {
 
     /**
-     * Order in ascending fashion
-     *
-     * @since 3.0.0-incubating
-     * @deprecated As of release 3.3.4, replaced by {@link #asc}.
-     */
-    @Deprecated
-    incr {
-        @Override
-        public int compare(final Object first, final Object second) {
-            return asc.compare(first, second);
-        }
-
-        @Override
-        public Order reversed() {
-            return decr;
-        }
-    },
-
-    /**
-     * Order in descending fashion.
-     *
-     * @since 3.0.0-incubating
-     * @deprecated As of release 3.3.4, replaced by {@link #desc}.
-     */
-    @Deprecated
-    decr {
-        @Override
-        public int compare(final Object first, final Object second) {
-            return desc.compare(first, second);
-        }
-
-        @Override
-        public Order reversed() {
-            return incr;
-        }
-    },
-
-    /**
-     * Order in a random fashion.
+     * Order in a random fashion. While this enum implements {@code Comparator}, the {@code compare(a,b)} method is not
+     * supported as a direct call. This change to the implementation of {@code compare(a,b)} occurred at 3.5.0 but
+     * this implementation was never used directly within the TinkerPop code base.
      *
      * @since 3.0.0-incubating
      */
     shuffle {
         @Override
         public int compare(final Object first, final Object second) {
-            return RANDOM.nextBoolean() ? -1 : 1;
+            throw new UnsupportedOperationException("Order.shuffle should not be used as an actual Comparator - it is a marker only");
         }
 
         @Override
@@ -87,11 +51,13 @@
     },
 
     /**
-     * Order in ascending fashion
+     * Order in ascending fashion.
      *
      * @since 3.3.4
      */
     asc {
+        private final Comparator<Comparable> ascendingComparator = Comparator.nullsFirst(Comparator.<Comparable>naturalOrder());
+
         @Override
         public int compare(final Object first, final Object second) {
             // need to convert enum to string representations for comparison or else you can get cast exceptions.
@@ -100,7 +66,7 @@
             final Object s = second instanceof Enum<?> ? ((Enum<?>) second).name() : second;
             return f instanceof Number && s instanceof Number
                     ? NumberHelper.compare((Number) f, (Number) s)
-                    : Comparator.<Comparable>naturalOrder().compare((Comparable) f, (Comparable) s);
+                    : ascendingComparator.compare((Comparable) f, (Comparable) s);
         }
 
         @Override
@@ -115,6 +81,8 @@
      * @since 3.3.4
      */
     desc {
+        private final Comparator<Comparable> descendingComparator = Comparator.nullsLast(Comparator.<Comparable>reverseOrder());
+
         @Override
         public int compare(final Object first, final Object second) {
             // need to convert enum to string representations for comparison or else you can get cast exceptions.
@@ -123,7 +91,7 @@
             final Object s = second instanceof Enum<?> ? ((Enum<?>) second).name() : second;
             return f instanceof Number && s instanceof Number
                     ? NumberHelper.compare((Number) s, (Number) f)
-                    : Comparator.<Comparable>reverseOrder().compare((Comparable) f, (Comparable) s);
+                    : descendingComparator.compare((Comparable) f, (Comparable) s);
         }
 
         @Override
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Script.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Script.java
new file mode 100644
index 0000000..ff227df
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Script.java
@@ -0,0 +1,105 @@
+/*
+ *  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;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * General representation of script
+ *
+ * @author Stark Arya (sandszhou.zj@alibaba-inc.com)
+ */
+public final class Script {
+    private static final String KEY_PREFIX = "_args_";
+    private final StringBuilder  scriptBuilder;
+    private final Map<Object, String> parameters;
+
+    public Script() {
+        scriptBuilder = new StringBuilder();
+        parameters = new HashMap<>();
+    }
+
+    public void init() {
+        scriptBuilder.setLength(0);
+        parameters.clear();
+    }
+
+    public Script append(final String script) {
+       scriptBuilder.append(script);
+       return this;
+    }
+
+    public Script setCharAtEnd(final char ch) {
+        scriptBuilder.setCharAt(scriptBuilder.length() - 1, ch);
+        return this;
+    }
+
+    public <V> Script getBoundKeyOrAssign(final boolean withParameters, final V value) {
+        if (withParameters) {
+            if (!parameters.containsKey(value)) {
+                parameters.put(value, getNextBoundKey());
+            }
+            append(parameters.get(value));
+        } else {
+            append(value.toString());
+        }
+        return this;
+    }
+
+    public String getScript() {
+        return scriptBuilder.toString();
+    }
+
+    public Optional<Map<String,Object>> getParameters() {
+        return Optional.ofNullable(parameters.isEmpty() ? null : parameters.entrySet().stream().collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey)));
+    }
+
+    /**
+     * @return  a monotonically increasing key
+     */
+    private String getNextBoundKey() {
+        return KEY_PREFIX + parameters.size();
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder builder = new StringBuilder();
+        final List<String> strings = Stream.of(new Object[]{getScript(), getParameters()})
+                .filter(o -> null != o)
+                .filter(o -> {
+                    if (o instanceof Map) {
+                        return !((Map) o).isEmpty();
+                    } else {
+                        return !o.toString().isEmpty();
+                    }
+                })
+                .map(Object::toString).collect(Collectors.toList());
+        if (!strings.isEmpty()) {
+            builder.append('(');
+            builder.append(String.join(",", strings));
+            builder.append(')');
+        }
+        return "Script[" + builder.toString() + "]";
+    }
+}
\ No newline at end of file
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Step.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Step.java
index a216783..6bc34f5 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Step.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Step.java
@@ -19,6 +19,7 @@
 package org.apache.tinkerpop.gremlin.process.traversal;
 
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.EmptyStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.ReducingBarrierStep;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
 
 import java.io.Serializable;
@@ -54,6 +55,14 @@
     public void addStart(final Traverser.Admin<S> start);
 
     /**
+     * Determines if starts objects are present without iterating forward. This function has special applicability
+     * around {@link ReducingBarrierStep} implementations where they always return {@code true} for calls to
+     * {@link #hasNext()}. Using this function gives insight to what the step itself is holding in its iterator without
+     * performing any sort of processing on the step itself.
+     */
+    public boolean hasStarts();
+
+    /**
      * Set the step that is previous to the current step.
      * Used for linking steps together to form a function chain.
      *
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Translator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Translator.java
index c2efdca..30dccc4 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Translator.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Translator.java
@@ -19,6 +19,19 @@
 
 package org.apache.tinkerpop.gremlin.process.traversal;
 
+import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.TraversalStrategyProxy;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+import org.apache.tinkerpop.gremlin.util.function.Lambda;
+
+import java.sql.Timestamp;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
 import java.util.function.BiFunction;
 
 /**
@@ -27,28 +40,38 @@
  * The parameterization of Translator is S (traversal source) and T (full translation).
  *
  * @author Marko A. Rodriguez (http://markorodriguez.com)
+ * @author Stark Arya (sandszhou.zj@alibaba-inc.com)
+ * @author Stephen Mallette (http://stephen.genoprime.com)
  */
 public interface Translator<S, T> {
 
     /**
      * Get the {@link TraversalSource} representation rooting this translator.
      * For string-based translators ({@link ScriptTranslator}), this is typically a "g".
-     * For java-based translators ({@link StepTranslator}), this is typically the {@link TraversalSource} instance which the {@link Traversal} will be built from.
+     * For java-based translators ({@link StepTranslator}), this is typically the {@link TraversalSource} instance
+     * which the {@link Traversal} will be built from.
      *
      * @return the traversal source representation
      */
     public S getTraversalSource();
 
     /**
-     * Translate {@link Bytecode} into a new representation.
-     * Typically, for language translations, the translation is to a string represenging the traversal in the respective scripting language.
+     * Translate {@link Bytecode} into a new representation. Typically, for language translations, the translation is
+     * to a string representing the traversal in the respective scripting language.
      *
-     * @param bytecode the byte code representing traversal source and traversal manipulations.
+     * @param bytecode the bytecode representing traversal source and traversal manipulations.
      * @return the translated object
      */
     public T translate(final Bytecode bytecode);
 
     /**
+     * Translates a {@link Traversal} into the specified form
+     */
+    public default T translate(final Traversal<?,?> t) {
+        return translate(t.asAdmin().getBytecode());
+    }
+
+    /**
      * Get the language that the translator is converting the traversal byte code to.
      *
      * @return the language of the translation
@@ -58,21 +81,254 @@
     ///
 
     /**
-     * Translates bytecode to a string representation.
+     * Translates bytecode to a Script representation.
      */
-    public interface ScriptTranslator extends Translator<String, String> {
+    public interface ScriptTranslator extends Translator<String, Script> {
 
         /**
          * Provides a way for the {@link ScriptTranslator} to convert various data types to their string
          * representations in their target language.
          */
-        public interface TypeTranslator extends BiFunction<String, Object, Object> { }
+        public interface TypeTranslator extends BiFunction<String, Object, Script> { }
 
-        /**
-         * Translates a {@link Traversal} into a script form.
-         */
-        public default String translate(final Traversal<?,?> t) {
-            return translate(t.asAdmin().getBytecode());
+        public abstract class AbstractTypeTranslator implements ScriptTranslator.TypeTranslator {
+            protected static final String ANONYMOUS_TRAVERSAL_PREFIX = "__";
+            protected final boolean withParameters;
+            protected final Script script;
+
+            protected AbstractTypeTranslator(final boolean withParameters) {
+                this.withParameters = withParameters;
+                this.script = new Script();
+            }
+
+            @Override
+            public Script apply(final String traversalSource, final Object o) {
+                this.script.init();
+                if (o instanceof Bytecode) {
+                    return produceScript(traversalSource, (Bytecode) o);
+                } else {
+                    return convertToScript(o);
+                }
+            }
+
+            /**
+             * Gets the syntax for the spawn of an anonymous traversal which is traditionally the double underscore.
+             */
+            protected String getAnonymousTraversalPrefix() {
+                return ANONYMOUS_TRAVERSAL_PREFIX;
+            }
+
+            /**
+             * Gets the syntax for a {@code null} value as a string representation.
+             */
+            protected abstract String getNullSyntax();
+
+            /**
+             * Take the string argument and convert it to a string representation in the target language (i.e. escape,
+             * enclose in appropriate quotes, etc.)
+             */
+            protected abstract String getSyntax(final String o);
+
+            /**
+             * Take the boolean argument and convert it to a string representation in the target language.
+             */
+            protected abstract String getSyntax(final Boolean o);
+
+            /**
+             * Take the {@code Date} argument and convert it to a string representation in the target language.
+             */
+            protected abstract String getSyntax(final Date o);
+
+            /**
+             * Take the {@code Timestamp} argument and convert it to a string representation in the target language.
+             */
+            protected abstract String getSyntax(final Timestamp o);
+
+            /**
+             * Take the {@code UUID} argument and convert it to a string representation in the target language.
+             */
+            protected abstract String getSyntax(final UUID o);
+
+            /**
+             * Take the {@link Lambda} argument and convert it to a string representation in the target language.
+             */
+            protected abstract String getSyntax(final Lambda o);
+
+            /**
+             * Take the {@link SackFunctions.Barrier} argument and convert it to a string representation in the target language.
+             */
+            protected abstract String getSyntax(final SackFunctions.Barrier o);
+
+            /**
+             * Take the {@link VertexProperty.Cardinality} argument and convert it to a string representation in the target language.
+             */
+            protected abstract String getSyntax(final VertexProperty.Cardinality o);
+
+            /**
+             * Take the {@link TraversalOptionParent.Pick} argument and convert it to a string representation in the target language.
+             */
+            protected abstract String getSyntax(final TraversalOptionParent.Pick o);
+
+            /**
+             * Take the numeric argument and convert it to a string representation in the target language. Languages
+             * that can discern differences in types of numbers will wish to further check the type of the
+             * {@code Number} instance itself (i.e. {@code Double}, {@code Integer}, etc.)
+             */
+            protected abstract String getSyntax(final Number o);
+
+            /**
+             * Take the {@code Set} and writes the syntax directly to the member {@link #script} variable.
+             */
+            protected abstract Script produceScript(final Set<?> o);
+
+            /**
+             * Take the {@code List} and writes the syntax directly to the member {@link #script} variable.
+             */
+            protected abstract Script produceScript(final List<?> o);
+
+            /**
+             * Take the {@code Map} and writes the syntax directly to the member {@link #script} variable.
+             */
+            protected abstract Script produceScript(final Map<?,?> o);
+
+            /**
+             * Take the {@code Class} and writes the syntax directly to the member {@link #script} variable.
+             */
+            protected abstract Script produceScript(final Class<?> o);
+
+            /**
+             * Take the {@code Enum} and writes the syntax directly to the member {@link #script} variable.
+             */
+            protected abstract Script produceScript(final Enum<?> o);
+
+            /**
+             * Take the {@link Vertex} and writes the syntax directly to the member {@link #script} variable.
+             */
+            protected abstract Script produceScript(final Vertex o);
+
+            /**
+             * Take the {@link Edge} and writes the syntax directly to the member {@link #script} variable.
+             */
+            protected abstract Script produceScript(final Edge o);
+
+            /**
+             * Take the {@link VertexProperty} and writes the syntax directly to the member {@link #script} variable.
+             */
+            protected abstract Script produceScript(final VertexProperty<?> o);
+
+            /**
+             * Take the {@link TraversalStrategyProxy} and writes the syntax directly to the member {@link #script} variable.
+             */
+            protected abstract Script produceScript(final TraversalStrategyProxy<?> o);
+
+            /**
+             * Take the {@link Bytecode} and writes the syntax directly to the member {@link #script} variable.
+             */
+            protected abstract Script produceScript(final String traversalSource, final Bytecode o);
+
+            /**
+             * Take the {@link P} and writes the syntax directly to the member {@link #script} variable. This
+             * implementation should also consider {@link TextP}.
+             */
+            protected abstract Script produceScript(final P<?> p);
+
+            /**
+             *  For each operator argument, if withParameters set true, try parametrization as follows:
+             *
+             *  -----------------------------------------------
+             *  if unpack, why ?      ObjectType
+             *  -----------------------------------------------
+             *  (Yes)                 Bytecode.Binding
+             *  (Recursion, No)       Bytecode
+             *  (Recursion, No)       Traversal
+             *  (Yes)                 String
+             *  (Recursion, No)       Set
+             *  (Recursion, No)       List
+             *  (Recursion, No)       Map
+             *  (Yes)                 Long
+             *  (Yes)                 Double
+             *  (Yes)                 Float
+             *  (Yes)                 Integer
+             *  (Yes)                 Timestamp
+             *  (Yes)                 Date
+             *  (Yes)                 Uuid
+             *  (Recursion, No)       P
+             *  (Enumeration, No)     SackFunctions.Barrier
+             *  (Enumeration, No)     VertexProperty.Cardinality
+             *  (Enumeration, No)     TraversalOptionParent.Pick
+             *  (Enumeration, No)     Enum
+             *  (Recursion, No)       Vertex
+             *  (Recursion, No)       Edge
+             *  (Recursion, No)       VertexProperty
+             *  (Yes)                 Lambda
+             *  (Recursion, No)       TraversalStrategyProxy
+             *  (Enumeration, No)     TraversalStrategy
+             *  (Yes)                 Other
+             *  -------------------------------------------------
+             *
+             * @param object
+             * @return String Repres
+             */
+            protected Script convertToScript(final Object object) {
+                if (object instanceof Bytecode.Binding) {
+                    return script.getBoundKeyOrAssign(withParameters, ((Bytecode.Binding) object).variable());
+                } else if (object instanceof Bytecode) {
+                    return produceScript(getAnonymousTraversalPrefix(), (Bytecode) object);
+                } else if (object instanceof Traversal) {
+                    return convertToScript(((Traversal) object).asAdmin().getBytecode());
+                } else if (object instanceof String) {
+                    final Object objectOrWrapper = withParameters ? object : getSyntax((String) object);
+                    return script.getBoundKeyOrAssign(withParameters, objectOrWrapper);
+                } else if (object instanceof Boolean) {
+                    final Object objectOrWrapper = withParameters ? object : getSyntax((Boolean) object);
+                    return script.getBoundKeyOrAssign(withParameters, objectOrWrapper);
+                } else if (object instanceof Set) {
+                    return produceScript((Set<?>) object);
+                } else if (object instanceof List) {
+                    return produceScript((List<?>) object);
+                } else if (object instanceof Map) {
+                    return produceScript((Map<?, ?>) object);
+                } else if (object instanceof Number) {
+                    final Object objectOrWrapper = withParameters ? object : getSyntax((Number) object);
+                    return script.getBoundKeyOrAssign(withParameters, objectOrWrapper);
+                } else if (object instanceof Class) {
+                    return produceScript((Class<?>) object);
+                } else if (object instanceof Timestamp) {
+                    final Object objectOrWrapper = withParameters ? object : getSyntax((Timestamp) object);
+                    return script.getBoundKeyOrAssign(withParameters, objectOrWrapper);
+                } else if (object instanceof Date) {
+                    final Object objectOrWrapper = withParameters ? object : getSyntax((Date) object);
+                    return script.getBoundKeyOrAssign(withParameters, objectOrWrapper);
+                } else if (object instanceof UUID) {
+                    final Object objectOrWrapper = withParameters ? object : getSyntax((UUID) object);
+                    return script.getBoundKeyOrAssign(withParameters, objectOrWrapper);
+                } else if (object instanceof P) {
+                    return produceScript((P<?>) object);
+                } else if (object instanceof SackFunctions.Barrier) {
+                    return script.append(getSyntax((SackFunctions.Barrier) object));
+                } else if (object instanceof VertexProperty.Cardinality) {
+                    return script.append(getSyntax((VertexProperty.Cardinality) object));
+                } else if (object instanceof TraversalOptionParent.Pick) {
+                    return script.append(getSyntax((TraversalOptionParent.Pick) object));
+                } else if (object instanceof Enum) {
+                    return produceScript((Enum<?>) object);
+                } else if (object instanceof Vertex) {
+                    return produceScript((Vertex) object);
+                } else if (object instanceof Edge) {
+                    return produceScript((Edge) object);
+                } else if (object instanceof VertexProperty) {
+                    return produceScript((VertexProperty<?>) object);
+                } else if (object instanceof Lambda) {
+                    final Object objectOrWrapper = withParameters ? object : getSyntax((Lambda) object);
+                    return script.getBoundKeyOrAssign(withParameters,objectOrWrapper);
+                } else if (object instanceof TraversalStrategyProxy) {
+                    return produceScript((TraversalStrategyProxy<?>) object);
+                } else if (object instanceof TraversalStrategy) {
+                    return convertToScript(new TraversalStrategyProxy(((TraversalStrategy) object)));
+                } else {
+                    return null == object ? script.append(getNullSyntax()) : script.getBoundKeyOrAssign(withParameters, object);
+                }
+            }
         }
     }
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Traversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Traversal.java
index b1b45f3..039a8ca 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Traversal.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Traversal.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
 import org.apache.tinkerpop.gremlin.process.remote.traversal.step.map.RemoteStep;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
@@ -153,7 +153,7 @@
     /**
      * Starts a promise to execute a function on the current {@code Traversal} that will be completed in the future.
      * Note that this method can only be used if the {@code Traversal} is constructed using
-     * {@link TraversalSource#withRemote(Configuration)}. Calling this method otherwise will yield an
+     * {@link AnonymousTraversalSource#withRemote(Configuration)}. Calling this method otherwise will yield an
      * {@code IllegalStateException}.
      */
     public default <T> CompletableFuture<T> promise(final Function<Traversal<S, E>, T> traversalFunction) {
@@ -419,15 +419,17 @@
         /**
          * Apply the registered {@link TraversalStrategies} to the traversal.
          * Once the strategies are applied, the traversal is "locked" and can no longer have steps added to it.
-         * The order of operations for strategy applications should be: globally id steps, apply strategies to root traversal, then to nested traversals.
+         * The order of operations for strategy applications should be: globally id steps, apply each strategy in turn
+         * to root traversal, then recursively to nested traversals.
          *
          * @throws IllegalStateException if the {@link TraversalStrategies} have already been applied
          */
         public void applyStrategies() throws IllegalStateException;
 
         /**
-         * Get the {@link TraverserGenerator} associated with this traversal. The traversal generator creates
-         * {@link Traverser} instances that are respective of the traversal's {@link TraverserRequirement}.
+         * Get the {@link TraverserGenerator} associated with this traversal.
+         * The traversal generator creates {@link Traverser} instances that are respective of the traversal's
+         * {@link TraverserRequirement}.
          *
          * @return the generator of traversers
          */
@@ -490,22 +492,30 @@
         public TraversalStrategies getStrategies();
 
         /**
-         * Set the {@link TraversalParent} {@link Step} that is the parent of this traversal.
-         * Traversals can be nested and this is the means by which the traversal tree is connected.
+         * Set the {@link TraversalParent} {@link Step} that is the parent of this traversal. Traversals can be nested
+         * and this is the means by which the traversal tree is connected. If there is no parent, then it should be a
+         * {@link EmptyStep}.
          *
-         * @param step the traversal holder parent step
+         * @param step the traversal holder parent step or {@link EmptyStep} if it has no parent
          */
         public void setParent(final TraversalParent step);
 
         /**
-         * Get the {@link TraversalParent} {@link Step} that is the parent of this traversal.
-         * Traversals can be nested and this is the means by which the traversal tree is walked.
+         * Get the {@link TraversalParent} {@link Step} that is the parent of this traversal. Traversals can be nested
+         * and this is the means by which the traversal tree is walked.
          *
-         * @return the traversal holder parent step
+         * @return the traversal holder parent step or {@link EmptyStep} if it has no parent.
          */
         public TraversalParent getParent();
 
         /**
+         * Determines if the traversal is at the root level.
+         */
+        public default boolean isRoot() {
+            return getParent() instanceof EmptyStep;
+        }
+
+        /**
          * Cloning is used to duplicate the traversal typically in OLAP environments.
          *
          * @return The cloned traversal
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalSource.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalSource.java
index 04fdf01..31f0701 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalSource.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalSource.java
@@ -18,26 +18,20 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal;
 
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.PropertiesConfiguration;
 import org.apache.tinkerpop.gremlin.process.computer.Computer;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
 import org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy;
-import org.apache.tinkerpop.gremlin.process.remote.RemoteConnection;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.OptionsStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SackStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SideEffectStrategy;
 import org.apache.tinkerpop.gremlin.structure.Graph;
 import org.apache.tinkerpop.gremlin.util.function.ConstantSupplier;
 
-import java.lang.reflect.Constructor;
 import java.util.Optional;
 import java.util.function.BinaryOperator;
 import java.util.function.Supplier;
 import java.util.function.UnaryOperator;
 
-import static org.apache.tinkerpop.gremlin.process.remote.RemoteConnection.GREMLIN_REMOTE_CONNECTION_CLASS;
-
 /**
  * A {@code TraversalSource} is used to create {@link Traversal} instances.
  * A traversal source can generate any number of {@link Traversal} instances.
@@ -373,53 +367,7 @@
         return clone;
     }
 
-    /**
-     * Configures the {@code TraversalSource} as a "remote" to issue the {@link Traversal} for execution elsewhere.
-     * Expects key for {@link RemoteConnection#GREMLIN_REMOTE_CONNECTION_CLASS} as well as any configuration required by
-     * the underlying {@link RemoteConnection} which will be instantiated. Note that the {@code Configuration} object
-     * is passed down without change to the creation of the {@link RemoteConnection} instance.
-     *
-     * @deprecated As of release 3.3.5, replaced by {@link AnonymousTraversalSource#withRemote(Configuration)}.
-     * @see <a href="https://issues.apache.org/jira/browse/TINKERPOP-2078">TINKERPOP-2078</a>
-     */
-    @Deprecated
-    public default TraversalSource withRemote(final Configuration conf) {
-        if (!conf.containsKey(GREMLIN_REMOTE_CONNECTION_CLASS))
-            throw new IllegalArgumentException("Configuration must contain the '" + GREMLIN_REMOTE_CONNECTION_CLASS + "' key");
-        final RemoteConnection remoteConnection;
-        try {
-            final Class<? extends RemoteConnection> clazz = Class.forName(conf.getString(GREMLIN_REMOTE_CONNECTION_CLASS)).asSubclass(RemoteConnection.class);
-            final Constructor<? extends RemoteConnection> ctor = clazz.getConstructor(Configuration.class);
-            remoteConnection = ctor.newInstance(conf);
-        } catch (Exception ex) {
-            throw new IllegalStateException(ex);
-        }
-        return withRemote(remoteConnection);
-    }
-    /**
-     * Configures the {@code TraversalSource} as a "remote" to issue the {@link Traversal} for execution elsewhere.
-     * Calls {@link #withRemote(Configuration)} after reading the properties file specified.
-     *
-     * @deprecated As of release 3.3.5, replaced by {@link AnonymousTraversalSource#withRemote(String)}.
-     * @see <a href="https://issues.apache.org/jira/browse/TINKERPOP-2078">TINKERPOP-2078</a>
-     */
-    @Deprecated
-    public default TraversalSource withRemote(final String configFile) throws Exception {
-        return withRemote(new PropertiesConfiguration(configFile));
-    }
-    /**
-     * Configures the {@code TraversalSource} as a "remote" to issue the {@link Traversal} for execution elsewhere.
-     * Implementations should track {@link RemoteConnection} instances that are created and call
-     * {@link RemoteConnection#close()} on them when the {@code TraversalSource} itself is closed.
-     *
-     * @param connection the {@link RemoteConnection} instance to use to submit the {@link Traversal}.
-     * @deprecated As of release 3.3.5, replaced by {@link AnonymousTraversalSource#withRemote(RemoteConnection)}.
-     * @see <a href="https://issues.apache.org/jira/browse/TINKERPOP-2078">TINKERPOP-2078</a>
-     */
-    @Deprecated
-    public TraversalSource withRemote(final RemoteConnection connection);
-
-    public default Optional<Class> getAnonymousTraversalClass() {
+    public default Optional<Class<?>> getAnonymousTraversalClass() {
         return Optional.empty();
     }
 
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 6c2c2f3..01deea1 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
@@ -27,7 +27,9 @@
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.AdjacentToIncidentStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.CountStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.EarlyLimitStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.ByModulatorOptimizationStrategy;
 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.InlineFilterStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.LazyBarrierStrategy;
@@ -41,6 +43,7 @@
 import org.apache.tinkerpop.gremlin.process.traversal.util.DefaultTraversalStrategies;
 import org.apache.tinkerpop.gremlin.structure.Graph;
 import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
+import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 import org.apache.tinkerpop.gremlin.util.tools.MultiMap;
 
 import java.io.Serializable;
@@ -49,6 +52,7 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
@@ -64,14 +68,22 @@
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  * @author Matthias Broecheler (me@matthiasb.com)
  */
-public interface TraversalStrategies extends Serializable, Cloneable {
+public interface TraversalStrategies extends Serializable, Cloneable, Iterable<TraversalStrategy<?>> {
 
     static List<Class<? extends TraversalStrategy>> STRATEGY_CATEGORIES = Collections.unmodifiableList(Arrays.asList(TraversalStrategy.DecorationStrategy.class, TraversalStrategy.OptimizationStrategy.class, TraversalStrategy.ProviderOptimizationStrategy.class, TraversalStrategy.FinalizationStrategy.class, TraversalStrategy.VerificationStrategy.class));
 
     /**
-     * Return all the {@link TraversalStrategy} singleton instances associated with this {@link TraversalStrategies}.
+     * Return an immutable list of the {@link TraversalStrategy} instances.
      */
-    public List<TraversalStrategy<?>> toList();
+    public default List<TraversalStrategy<?>> toList() {
+        return Collections.unmodifiableList(IteratorUtils.list(iterator()));
+    }
+
+    /**
+     * Return an {@code Iterator} of the {@link TraversalStrategy} instances.
+     */
+    @Override
+    public Iterator<TraversalStrategy<?>> iterator();
 
     /**
      * Return the {@link TraversalStrategy} instance associated with the provided class.
@@ -81,23 +93,14 @@
      * @return an optional containing the strategy instance or not
      */
     public default <T extends TraversalStrategy> Optional<T> getStrategy(final Class<T> traversalStrategyClass) {
-        return (Optional) toList().stream().filter(s -> traversalStrategyClass.isAssignableFrom(s.getClass())).findAny();
+        return (Optional<T>) IteratorUtils.stream(iterator()).
+                filter(s -> traversalStrategyClass.isAssignableFrom(s.getClass())).findAny();
     }
 
     /**
-     * Apply all the {@link TraversalStrategy} optimizers to the {@link Traversal}. This method must ensure that the
-     * strategies are sorted prior to application.
-     *
-     * @param traversal the traversal to apply the strategies to
-     * @deprecated As of release 3.3.10, not directly replaced as this mode of strategy application has not been
-     * utilized since early days of 3.x
-     */
-    @Deprecated
-    public void applyStrategies(final Traversal.Admin<?, ?> traversal);
-
-    /**
-     * Add all the provided {@link TraversalStrategy} instances to the current collection.
-     * When all the provided strategies have been added, the collection is resorted.
+     * Add all the provided {@link TraversalStrategy} instances to the current collection. When all the provided
+     * strategies have been added, the collection is resorted. If a strategy class is found to already be defined, it
+     * is removed and replaced by the newly added one.
      *
      * @param strategies the traversal strategies to add
      * @return the newly updated/sorted traversal strategies collection
@@ -135,7 +138,6 @@
             MultiMap.put(strategiesByCategory, s.getTraversalCategory(), s.getClass());
         });
 
-
         //Initialize all the dependencies
         strategies.forEach(strategy -> {
             strategy.applyPrior().forEach(s -> {
@@ -190,7 +192,6 @@
                     + seenStrategyClases + ']');
         }
 
-
         if (unprocessedStrategyClasses.contains(strategyClass)) {
             seenStrategyClases.add(strategyClass);
             for (Class<? extends TraversalStrategy> dependency : MultiMap.get(dependencyMap, strategyClass)) {
@@ -208,7 +209,7 @@
          * Keeps track of {@link GraphComputer} and/or {@link Graph} classes that have been initialized to the
          * classloader so that they do not have to be reflected again.
          */
-        private static Set<Class> LOADED = ConcurrentHashMap.newKeySet();
+        private static final Set<Class<?>> LOADED = ConcurrentHashMap.newKeySet();
 
         private static final Map<Class<? extends Graph>, TraversalStrategies> GRAPH_CACHE = new HashMap<>();
         private static final Map<Class<? extends GraphComputer>, TraversalStrategies> GRAPH_COMPUTER_CACHE = new HashMap<>();
@@ -216,11 +217,13 @@
         static {
             final TraversalStrategies graphStrategies = new DefaultTraversalStrategies();
             graphStrategies.addStrategies(
+                    IdentityRemovalStrategy.instance(),
                     ConnectiveStrategy.instance(),
                     EarlyLimitStrategy.instance(),
                     InlineFilterStrategy.instance(),
                     IncidentToAdjacentStrategy.instance(),
                     AdjacentToIncidentStrategy.instance(),
+                    ByModulatorOptimizationStrategy.instance(),
                     FilterRankingStrategy.instance(),
                     MatchPredicateStrategy.instance(),
                     RepeatUnrollStrategy.instance(),
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalStrategy.java
index 2aa4153..b4e5423 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalStrategy.java
@@ -18,8 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.PartitionStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization.ProfileStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.CountStrategy;
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 e07bec1..fc58c62 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
@@ -18,9 +18,11 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal;
 
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.LoopsStep;
 import org.apache.tinkerpop.gremlin.structure.util.Attachable;
 
 import java.io.Serializable;
+import java.util.Comparator;
 import java.util.Set;
 import java.util.function.Function;
 
@@ -134,7 +136,12 @@
      */
     @Override
     public default int compareTo(final Traverser<T> other) throws ClassCastException {
-        return ((Comparable) this.get()).compareTo(other.get());
+        final Object thisObj = this.get();
+        final Object otherObj = other.get();
+        if (thisObj == otherObj) return 0;
+        if (null == thisObj) return -1;
+        if (null == otherObj) return 1;
+        return ((Comparable) thisObj).compareTo(otherObj);
     }
 
     /**
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/GremlinDslProcessor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/GremlinDslProcessor.java
index f40d870..295efcd 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/GremlinDslProcessor.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/GremlinDslProcessor.java
@@ -27,6 +27,7 @@
 import com.squareup.javapoet.TypeName;
 import com.squareup.javapoet.TypeSpec;
 import com.squareup.javapoet.TypeVariableName;
+import com.squareup.javapoet.WildcardTypeName;
 import org.apache.tinkerpop.gremlin.process.remote.RemoteConnection;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
@@ -57,10 +58,10 @@
 import javax.lang.model.element.TypeElement;
 import javax.lang.model.element.VariableElement;
 import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.NoType;
 import javax.lang.model.type.TypeKind;
 import javax.lang.model.type.TypeMirror;
 import javax.lang.model.type.TypeVariable;
+import javax.lang.model.type.WildcardType;
 import javax.lang.model.util.Elements;
 import javax.lang.model.util.Types;
 import javax.tools.Diagnostic;
@@ -355,7 +356,8 @@
                     .addModifiers(Modifier.PUBLIC)
                     .addAnnotation(Override.class)
                     .addStatement("return Optional.of(__.class)")
-                    .returns(ParameterizedTypeName.get(Optional.class, Class.class))
+                    .returns(ParameterizedTypeName.get(ClassName.get(Optional.class),
+                             ParameterizedTypeName.get(ClassName.get(Class.class), WildcardTypeName.subtypeOf(Object.class))))
                     .build());
         }
 
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 1df9976..3baac05 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
@@ -125,7 +125,7 @@
 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.AggregateGlobalStep;
 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;
@@ -136,12 +136,13 @@
 import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.SackValueStep;
 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.AggregateLocalStep;
 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.HasContainer;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.WithOptions;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.TraverserSet;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalMetrics;
@@ -155,7 +156,6 @@
 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.util.empty.EmptyGraph;
 import org.apache.tinkerpop.gremlin.util.function.ConstantSupplier;
 
 import java.util.ArrayList;
@@ -172,6 +172,8 @@
 import java.util.function.Function;
 import java.util.function.Predicate;
 
+import static org.apache.tinkerpop.gremlin.structure.VertexProperty.Cardinality.single;
+
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  * @author Stephen Mallette (http://stephen.genoprime.com)
@@ -551,7 +553,7 @@
      */
     public default <E2> GraphTraversal<S, Map<String, E2>> propertyMap(final String... propertyKeys) {
         this.asAdmin().getBytecode().addStep(Symbols.propertyMap, propertyKeys);
-        return this.asAdmin().addStep(new PropertyMapStep<>(this.asAdmin(), false, PropertyType.PROPERTY, propertyKeys));
+        return this.asAdmin().addStep(new PropertyMapStep<>(this.asAdmin(), WithOptions.none, PropertyType.PROPERTY, propertyKeys));
     }
 
     /**
@@ -585,7 +587,7 @@
      */
     public default <E2> GraphTraversal<S, Map<Object, E2>> valueMap(final String... propertyKeys) {
         this.asAdmin().getBytecode().addStep(Symbols.valueMap, propertyKeys);
-        return this.asAdmin().addStep(new PropertyMapStep<>(this.asAdmin(), false, PropertyType.VALUE, propertyKeys));
+        return this.asAdmin().addStep(new PropertyMapStep<>(this.asAdmin(), WithOptions.none, PropertyType.VALUE, propertyKeys));
     }
 
     /**
@@ -604,7 +606,7 @@
     @Deprecated
     public default <E2> GraphTraversal<S, Map<Object, E2>> valueMap(final boolean includeTokens, final String... propertyKeys) {
         this.asAdmin().getBytecode().addStep(Symbols.valueMap, includeTokens, propertyKeys);
-        return this.asAdmin().addStep(new PropertyMapStep<>(this.asAdmin(), includeTokens, PropertyType.VALUE, propertyKeys));
+        return this.asAdmin().addStep(new PropertyMapStep<>(this.asAdmin(), WithOptions.all, PropertyType.VALUE, propertyKeys));
     }
 
     /**
@@ -1047,7 +1049,7 @@
      */
     public default GraphTraversal<S, Vertex> addV(final Traversal<?, String> vertexLabelTraversal) {
         this.asAdmin().getBytecode().addStep(Symbols.addV, vertexLabelTraversal);
-        return this.asAdmin().addStep(new AddVertexStep<>(this.asAdmin(), vertexLabelTraversal.asAdmin()));
+        return this.asAdmin().addStep(new AddVertexStep<>(this.asAdmin(), null == vertexLabelTraversal ? null : vertexLabelTraversal.asAdmin()));
     }
 
     /**
@@ -1084,7 +1086,7 @@
      */
     public default GraphTraversal<S, Edge> addE(final Traversal<?, String> edgeLabelTraversal) {
         this.asAdmin().getBytecode().addStep(Symbols.addE, edgeLabelTraversal);
-        return this.asAdmin().addStep(new AddEdgeStep<>(this.asAdmin(), edgeLabelTraversal.asAdmin()));
+        return this.asAdmin().addStep(new AddEdgeStep<>(this.asAdmin(), null == edgeLabelTraversal ? null : edgeLabelTraversal.asAdmin()));
     }
 
     /**
@@ -1096,8 +1098,13 @@
      * @since 3.1.0-incubating
      */
     public default GraphTraversal<S, E> to(final String toStepLabel) {
+        final Step<?,?> prev = this.asAdmin().getEndStep();
+        if (!(prev instanceof FromToModulating))
+            throw new IllegalArgumentException(String.format(
+                    "The to() step cannot follow %s", prev.getClass().getSimpleName()));
+
         this.asAdmin().getBytecode().addStep(Symbols.to, toStepLabel);
-        ((FromToModulating) this.asAdmin().getEndStep()).addTo(toStepLabel);
+        ((FromToModulating) prev).addTo(toStepLabel);
         return this;
     }
 
@@ -1110,8 +1117,13 @@
      * @since 3.1.0-incubating
      */
     public default GraphTraversal<S, E> from(final String fromStepLabel) {
+        final Step<?,?> prev = this.asAdmin().getEndStep();
+        if (!(prev instanceof FromToModulating))
+            throw new IllegalArgumentException(String.format(
+                    "The from() step cannot follow %s", prev.getClass().getSimpleName()));
+
         this.asAdmin().getBytecode().addStep(Symbols.from, fromStepLabel);
-        ((FromToModulating) this.asAdmin().getEndStep()).addFrom(fromStepLabel);
+        ((FromToModulating) prev).addFrom(fromStepLabel);
         return this;
     }
 
@@ -1125,8 +1137,13 @@
      * @since 3.1.0-incubating
      */
     public default GraphTraversal<S, E> to(final Traversal<?, Vertex> toVertex) {
+        final Step<?,?> prev = this.asAdmin().getEndStep();
+        if (!(prev instanceof FromToModulating))
+            throw new IllegalArgumentException(String.format(
+                    "The to() step cannot follow %s", prev.getClass().getSimpleName()));
+
         this.asAdmin().getBytecode().addStep(Symbols.to, toVertex);
-        ((FromToModulating) this.asAdmin().getEndStep()).addTo(toVertex.asAdmin());
+        ((FromToModulating) prev).addTo(toVertex.asAdmin());
         return this;
     }
 
@@ -1140,8 +1157,13 @@
      * @since 3.1.0-incubating
      */
     public default GraphTraversal<S, E> from(final Traversal<?, Vertex> fromVertex) {
+        final Step<?,?> prev = this.asAdmin().getEndStep();
+        if (!(prev instanceof FromToModulating))
+            throw new IllegalArgumentException(String.format(
+                    "The from() step cannot follow %s", prev.getClass().getSimpleName()));
+
         this.asAdmin().getBytecode().addStep(Symbols.from, fromVertex);
-        ((FromToModulating) this.asAdmin().getEndStep()).addFrom(fromVertex.asAdmin());
+        ((FromToModulating) prev).addFrom(fromVertex.asAdmin());
         return this;
     }
 
@@ -1155,8 +1177,13 @@
      * @since 3.3.0
      */
     public default GraphTraversal<S, E> to(final Vertex toVertex) {
+        final Step<?,?> prev = this.asAdmin().getEndStep();
+        if (!(prev instanceof FromToModulating))
+            throw new IllegalArgumentException(String.format(
+                    "The to() step cannot follow %s", prev.getClass().getSimpleName()));
+
         this.asAdmin().getBytecode().addStep(Symbols.to, toVertex);
-        ((FromToModulating) this.asAdmin().getEndStep()).addTo(__.constant(toVertex).asAdmin());
+        ((FromToModulating) prev).addTo(__.constant(toVertex).asAdmin());
         return this;
     }
 
@@ -1170,8 +1197,13 @@
      * @since 3.3.0
      */
     public default GraphTraversal<S, E> from(final Vertex fromVertex) {
+        final Step<?,?> prev = this.asAdmin().getEndStep();
+        if (!(prev instanceof FromToModulating))
+            throw new IllegalArgumentException(String.format(
+                    "The from() step cannot follow %s", prev.getClass().getSimpleName()));
+
         this.asAdmin().getBytecode().addStep(Symbols.from, fromVertex);
-        ((FromToModulating) this.asAdmin().getEndStep()).addFrom(__.constant(fromVertex).asAdmin());
+        ((FromToModulating) prev).addFrom(__.constant(fromVertex).asAdmin());
         return this;
     }
 
@@ -2008,13 +2040,13 @@
      * with a {@link Scope#local}.
      *
      * @param sideEffectKey the name of the side-effect key that will hold the aggregated objects
-     * @return the traversal with an appended {@link AggregateStep}
+     * @return the traversal with an appended {@link AggregateGlobalStep}
      * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#aggregate-step" target="_blank">Reference Documentation - Aggregate Step</a>
      * @since 3.0.0-incubating
      */
     public default GraphTraversal<S, E> aggregate(final String sideEffectKey) {
         this.asAdmin().getBytecode().addStep(Symbols.aggregate, sideEffectKey);
-        return this.asAdmin().addStep(new AggregateStep<>(this.asAdmin(), sideEffectKey));
+        return this.asAdmin().addStep(new AggregateGlobalStep<>(this.asAdmin(), sideEffectKey));
     }
 
     /**
@@ -2022,14 +2054,14 @@
      * {@link Scope#local} or eager ({@link Scope#global} while gathering those objects.
      *
      * @param sideEffectKey the name of the side-effect key that will hold the aggregated objects
-     * @return the traversal with an appended {@link AggregateStep}
+     * @return the traversal with an appended {@link AggregateGlobalStep}
      * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#aggregate-step" target="_blank">Reference Documentation - Aggregate Step</a>
      * @since 3.4.3
      */
     public default GraphTraversal<S, E> aggregate(final Scope scope, final String sideEffectKey) {
         this.asAdmin().getBytecode().addStep(Symbols.aggregate, scope, sideEffectKey);
         return this.asAdmin().addStep(scope == Scope.global ?
-                new AggregateStep<>(this.asAdmin(), sideEffectKey) : new StoreStep<>(this.asAdmin(), sideEffectKey));
+                new AggregateGlobalStep<>(this.asAdmin(), sideEffectKey) : new AggregateLocalStep<>(this.asAdmin(), sideEffectKey));
     }
 
     /**
@@ -2090,7 +2122,7 @@
      * Lazily aggregates objects in the stream into a side-effect collection.
      *
      * @param sideEffectKey the name of the side-effect key that will hold the aggregate
-     * @return the traversal with an appended {@link StoreStep}
+     * @return the traversal with an appended {@link AggregateLocalStep}
      * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#store-step" target="_blank">Reference Documentation - Store Step</a>
      * @since 3.0.0-incubating
      * @deprecated As of release 3.4.3, replaced by {@link #aggregate(Scope, String)} using {@link Scope#local}.
@@ -2098,7 +2130,7 @@
     @Deprecated
     public default GraphTraversal<S, E> store(final String sideEffectKey) {
         this.asAdmin().getBytecode().addStep(Symbols.store, sideEffectKey);
-        return this.asAdmin().addStep(new StoreStep<>(this.asAdmin(), sideEffectKey));
+        return this.asAdmin().addStep(new AggregateLocalStep<>(this.asAdmin(), sideEffectKey));
     }
 
     /**
@@ -2178,12 +2210,19 @@
             endStep = endStep.getPreviousStep();
         }
 
-        // edge properties can always be folded as there is no cardinality/metaproperties. for a vertex mutation,
-        // it's possible to fold the property() into the Mutating step if there are no metaproperties (i.e. keyValues)
-        // and if (1) the key is an instance of T OR OR (3) the key is a string and the cardinality is not specifiied.
-        // Note that checking for single cardinality of the argument doesn't work well because once folded we lose
-        // the cardinality argument associated to the key/value pair and then it relies on the graph. that
-        // means that if you do:
+        // edge properties can always be folded as there are no cardinality/metaproperties. of course, if the
+        // cardinality is specified as something other than single or null it would be confusing to simply allow it to
+        // execute and not throw an error.
+        if ((endStep instanceof AddEdgeStep || endStep instanceof AddEdgeStartStep) && (null != cardinality && cardinality != single))
+            throw new IllegalStateException(String.format(
+                    "Multi-property cardinality of [%s] can only be set for a Vertex but is being used for addE() with key: %s",
+                    cardinality.name(), key));
+
+        // for a vertex mutation, it's possible to fold the property() into the Mutating step if there are no
+        // metaproperties (i.e. keyValues) and if (1) the key is an instance of T OR OR (3) the key is a string and the
+        // cardinality is not specified. Note that checking for single cardinality of the argument doesn't work well
+        // because once folded we lose the cardinality argument associated to the key/value pair and then it relies on
+        // the graph. that means that if you do:
         //
         // g.addV().property(single, 'k',1).property(single,'k',2)
         //
@@ -2216,8 +2255,7 @@
      * {@link VertexProperty.Cardinality} is defaulted to {@code null} which  means that the default cardinality for
      * the {@link Graph} will be used.
      * <p/>
-     * This method is effectively calls
-     * {@link #property(org.apache.tinkerpop.gremlin.structure.VertexProperty.Cardinality, Object, Object, Object...)}
+     * This method is effectively calls {@link #property(VertexProperty.Cardinality, Object, Object, Object...)}
      * as {@code property(null, key, value, keyValues}.
      *
      * @param key       the key for the property
@@ -2229,8 +2267,8 @@
      */
     public default GraphTraversal<S, E> property(final Object key, final Object value, final Object... keyValues) {
         return key instanceof VertexProperty.Cardinality ?
-                this.property((VertexProperty.Cardinality) key, value, keyValues[0],
-                        keyValues.length > 1 ?
+                this.property((VertexProperty.Cardinality) key, value, null == keyValues ? null : keyValues[0],
+                        keyValues != null && keyValues.length > 1 ?
                                 Arrays.copyOfRange(keyValues, 1, keyValues.length) :
                                 new Object[]{}) :
                 this.property(null, key, value, keyValues);
@@ -2659,13 +2697,13 @@
      * Indexes all items of the current collection. The indexing format can be configured using the {@link GraphTraversal#with(String, Object)}
      * and {@link org.apache.tinkerpop.gremlin.process.traversal.step.util.WithOptions#indexer}.
      *
-     * Indexed as list: ["a","b","c"] => [["a",0],["b",1],["c",2]]
-     * Indexed as map:  ["a","b","c"] => {0:"a",1:"b",2:"c"}
+     * Indexed as list: ["a","b","c"] =&gt; [["a",0],["b",1],["c",2]]
+     * Indexed as map:  ["a","b","c"] =&gt; {0:"a",1:"b",2:"c"}
      *
      * If the current object is not a collection, this step will map the object to a single item collection/map:
      *
-     * Indexed as list: "a" => ["a",0]
-     * Indexed as map:  "a" => {0:"a"}
+     * Indexed as list: "a" =&gt; ["a",0]
+     * Indexed as map:  "a" =&gt; {0:"a"}
      *
      * @return the traversal with an appended {@link IndexStep}
      * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#index-step" target="_blank">Reference Documentation - Index Step</a>
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java
index f5c5c09..64fff5d 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java
@@ -18,12 +18,10 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.dsl.graph;
 
-import org.apache.commons.configuration.Configuration;
 import org.apache.tinkerpop.gremlin.process.computer.Computer;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
 import org.apache.tinkerpop.gremlin.process.remote.RemoteConnection;
 import org.apache.tinkerpop.gremlin.process.remote.traversal.strategy.decoration.RemoteStrategy;
-import org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource;
 import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
@@ -77,11 +75,6 @@
 
     ////////////////
 
-    @Override
-    public Optional<Class> getAnonymousTraversalClass() {
-        return Optional.of(__.class);
-    }
-
     public GraphTraversalSource(final Graph graph, final TraversalStrategies traversalStrategies) {
         this.graph = graph;
         this.strategies = traversalStrategies;
@@ -98,6 +91,11 @@
     }
 
     @Override
+    public Optional<Class<?>> getAnonymousTraversalClass() {
+        return Optional.of(__.class);
+    }
+
+    @Override
     public TraversalStrategies getStrategies() {
         return this.strategies;
     }
@@ -295,54 +293,12 @@
         return clone;
     }
 
-    /**
-     * {@inheritDoc}
-     *
-     * @deprecated As of release 3.3.5, replaced by {@link AnonymousTraversalSource#withRemote(Configuration)}.
-     * @see <a href="https://issues.apache.org/jira/browse/TINKERPOP-2078">TINKERPOP-2078</a>
-     */
-    @Override
-    @Deprecated
-    public GraphTraversalSource withRemote(final Configuration conf) {
-        return (GraphTraversalSource) TraversalSource.super.withRemote(conf);
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * @deprecated As of release 3.3.5, replaced by {@link AnonymousTraversalSource#withRemote(String)}.
-     * @see <a href="https://issues.apache.org/jira/browse/TINKERPOP-2078">TINKERPOP-2078</a>
-     */
-    @Override
-    @Deprecated
-    public GraphTraversalSource withRemote(final String configFile) throws Exception {
-        return (GraphTraversalSource) TraversalSource.super.withRemote(configFile);
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * @deprecated As of release 3.3.5, replaced by {@link AnonymousTraversalSource#withRemote(RemoteConnection)}.
-     * @see <a href="https://issues.apache.org/jira/browse/TINKERPOP-2078">TINKERPOP-2078</a>
-     */
-    @Override
-    @Deprecated
-    public GraphTraversalSource withRemote(final RemoteConnection connection) {
-        // check if someone called withRemote() more than once, so just release resources on the initial
-        // connection as you can't have more than one. maybe better to toss IllegalStateException??
-        if (this.connection != null)
-            throw new IllegalStateException(String.format("TraversalSource already configured with a RemoteConnection [%s]", connection));
-        final GraphTraversalSource clone = this.clone();
-        clone.connection = connection;
-        clone.getStrategies().addStrategies(new RemoteStrategy(connection));
-        return clone;
-    }
-
     //// SPAWNS
 
 
     /**
-     * Spawns a {@link GraphTraversal} by adding a vertex with the specified label.
+     * Spawns a {@link GraphTraversal} by adding a vertex with the specified label. If the {@code label} is
+     * {@code null} then it will default to {@link Vertex#DEFAULT_LABEL}.
      */
     public GraphTraversal<Vertex, Vertex> addV(final String label) {
         final GraphTraversalSource clone = this.clone();
@@ -352,7 +308,8 @@
     }
 
     /**
-     * Spawns a {@link GraphTraversal} by adding a vertex with the label as determined by a {@link Traversal}.
+     * Spawns a {@link GraphTraversal} by adding a vertex with the label as determined by a {@link Traversal}. If the
+     * {@code vertexLabelTraversal} is {@code null} then it will default to {@link Vertex#DEFAULT_LABEL}.
      */
     public GraphTraversal<Vertex, Vertex> addV(final Traversal<?, String> vertexLabelTraversal) {
         final GraphTraversalSource clone = this.clone();
@@ -445,10 +402,21 @@
     }
 
     /**
-     * Proxies calls through to the underlying {@link Graph#tx()}.
+     * Proxies calls through to the underlying {@link Graph#tx()} or to the {@link RemoteConnection#tx()}.
      */
     public Transaction tx() {
-        return this.graph.tx();
+        if (null == this.connection)
+            return this.graph.tx();
+        else {
+            // prevent child transactions and let the current Transaction object be bound to the
+            // TraversalSource that spawned it
+            final Transaction tx = this.connection.tx();
+            if (tx == Transaction.NO_OP && this.connection instanceof Transaction)
+                return (Transaction) this.connection;
+            else
+                return tx;
+        }
+
     }
 
     /**
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/ElementValueTraversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/ElementValueTraversal.java
deleted file mode 100644
index 73f73a6..0000000
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/ElementValueTraversal.java
+++ /dev/null
@@ -1,95 +0,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.
- */
-package org.apache.tinkerpop.gremlin.process.traversal.lambda;
-
-import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
-import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil;
-import org.apache.tinkerpop.gremlin.structure.Element;
-
-import java.util.Map;
-import java.util.Objects;
-
-/**
- * More efficiently extracts a value from an {@link Element} or {@code Map} to avoid strategy application costs. Note
- * that as of 3.4.5 this class is now poorly named as it was originally designed to work with {@link Element} only.
- * In future 3.5.0 this class will likely be renamed but to ensure that we get this revised functionality for
- * {@code Map} without introducing a breaking change this name will remain the same.
- *
- * @author Marko A. Rodriguez (http://markorodriguez.com)
- */
-public final class ElementValueTraversal<V> extends AbstractLambdaTraversal<Element, V> {
-
-    private final String propertyKey;
-    private V value;
-
-    public ElementValueTraversal(final String propertyKey) {
-        this.propertyKey = propertyKey;
-    }
-
-    @Override
-    public V next() {
-        return this.value;
-    }
-
-    @Override
-    public boolean hasNext() {
-        return true;
-    }
-
-    @Override
-    public void addStart(final Traverser.Admin<Element> start) {
-        if (null == this.bypassTraversal) {
-            // playing a game of type erasure here.....technically we can process either Map or Element here in this
-            // case after 3.4.5. and obviously users get weird errors along those lines here anyway. will fix up the
-            // generics in 3.5.0 when we can take some breaking changes. seemed like this feature would make Gremlin
-            // a lot nicer and given the small footprint of the change this seemed like a good hack to take.
-            final Object o = start.get();
-            if (o instanceof Element)
-                this.value = ((Element) o).value(propertyKey);
-            else if (o instanceof Map)
-                this.value = (V) ((Map) o).get(propertyKey);
-            else
-                throw new IllegalStateException(String.format(
-                        "The by(\"%s\") modulator can only be applied to a traverser that is an Element or a Map - it is being applied to [%s] a %s class instead",
-                        propertyKey, o, o.getClass().getSimpleName()));
-        } else {
-            this.value = TraversalUtil.apply(start, this.bypassTraversal);
-        }
-    }
-
-    public String getPropertyKey() {
-        return this.propertyKey;
-    }
-
-    @Override
-    public String toString() {
-        return "value(" + (null == this.bypassTraversal ? this.propertyKey : this.bypassTraversal) + ')';
-    }
-
-    @Override
-    public int hashCode() {
-        return super.hashCode() ^ this.propertyKey.hashCode();
-    }
-
-    @Override
-    public boolean equals(final Object other) {
-        return other instanceof ElementValueTraversal
-                && Objects.equals(((ElementValueTraversal) other).propertyKey, this.propertyKey);
-    }
-}
\ No newline at end of file
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/TokenTraversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/TokenTraversal.java
index d41c402..e272ccf 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/TokenTraversal.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/TokenTraversal.java
@@ -20,6 +20,7 @@
 
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import org.apache.tinkerpop.gremlin.structure.Element;
+import org.apache.tinkerpop.gremlin.structure.Property;
 import org.apache.tinkerpop.gremlin.structure.T;
 
 import java.util.Objects;
@@ -27,7 +28,7 @@
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class TokenTraversal<S extends Element, E> extends AbstractLambdaTraversal<S, E> {
+public final class TokenTraversal<S, E> extends AbstractLambdaTraversal<S, E> {
 
     private E e;
     private final T t;
@@ -43,7 +44,21 @@
 
     @Override
     public void addStart(final Traverser.Admin<S> start) {
-        this.e = (E) this.t.apply(start.get());
+        final S s = start.get();
+        if (s instanceof Element)
+            this.e = (E) this.t.apply((Element) start.get());
+        else if (s instanceof Property) {
+            // T.apply() doesn't work on Property because the inheritance hierarchy doesn't make it an Element. have
+            // to special case it here. only T.key/value make any sense for it.
+            if (t == T.key)
+                this.e = (E) ((Property) s).key();
+            else if (t == T.value)
+                this.e = ((Property<E>) s).value();
+            else
+                throw new IllegalStateException(String.format("TokenTraversal support of Property does not allow selection by %s", t));
+        } else
+            throw new IllegalStateException(String.format("TokenTraversal support of %s does not allow selection by %s", s.getClass().getName(), t));
+
     }
 
     @Override
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/ValueTraversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/ValueTraversal.java
new file mode 100644
index 0000000..22d5661
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/ValueTraversal.java
@@ -0,0 +1,89 @@
+/*
+ * 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.lambda;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil;
+import org.apache.tinkerpop.gremlin.structure.Element;
+
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * More efficiently extracts a value from an {@link Element} or {@code Map} to avoid strategy application costs.
+ *
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public final class ValueTraversal<T, V> extends AbstractLambdaTraversal<T, V> {
+
+    private final String propertyKey;
+    private V value;
+
+    public ValueTraversal(final String propertyKey) {
+        this.propertyKey = propertyKey;
+    }
+
+    @Override
+    public V next() {
+        return this.value;
+    }
+
+    @Override
+    public boolean hasNext() {
+        return true;
+    }
+
+    @Override
+    public void addStart(final Traverser.Admin<T> start) {
+        if (null == this.bypassTraversal) {
+            final T o = start.get();
+            if (o instanceof Element)
+                this.value = (V)((Element) o).property(propertyKey).orElse(null);
+            else if (o instanceof Map)
+                this.value = (V) ((Map) o).get(propertyKey);
+            else
+                throw new IllegalStateException(String.format(
+                        "The by(\"%s\") modulator can only be applied to a traverser that is an Element or a Map - it is being applied to [%s] a %s class instead",
+                        propertyKey, o, o.getClass().getSimpleName()));
+        } else {
+            this.value = TraversalUtil.apply(start, this.bypassTraversal);
+        }
+    }
+
+    public String getPropertyKey() {
+        return this.propertyKey;
+    }
+
+    @Override
+    public String toString() {
+        return "value(" + (null == this.bypassTraversal ? this.propertyKey : this.bypassTraversal) + ')';
+    }
+
+    @Override
+    public int hashCode() {
+        return super.hashCode() ^ this.propertyKey.hashCode();
+    }
+
+    @Override
+    public boolean equals(final Object other) {
+        return other instanceof ValueTraversal
+                && Objects.equals(((ValueTraversal) other).propertyKey, this.propertyKey);
+    }
+}
\ No newline at end of file
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/ByModulating.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/ByModulating.java
index 01841fa..b808bf6 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/ByModulating.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/ByModulating.java
@@ -23,7 +23,7 @@
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
 import org.apache.tinkerpop.gremlin.process.traversal.lambda.ColumnTraversal;
-import org.apache.tinkerpop.gremlin.process.traversal.lambda.ElementValueTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.lambda.ValueTraversal;
 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.TokenTraversal;
@@ -47,7 +47,7 @@
     }
 
     public default void modulateBy(final String string) throws UnsupportedOperationException {
-        this.modulateBy(new ElementValueTraversal(string));
+        this.modulateBy(new ValueTraversal(string));
     }
 
     public default void modulateBy(final T token) throws UnsupportedOperationException {
@@ -74,7 +74,7 @@
     }
 
     public default void modulateBy(final String key, final Comparator comparator) {
-        this.modulateBy(new ElementValueTraversal<>(key), comparator);
+        this.modulateBy(new ValueTraversal<>(key), comparator);
     }
 
     public default void modulateBy(final Comparator comparator) {
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/Grouping.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/Grouping.java
new file mode 100644
index 0000000..1e15758
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/Grouping.java
@@ -0,0 +1,100 @@
+/*
+ * 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;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Step;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.process.traversal.lambda.ColumnTraversal;
+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.TokenTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.lambda.ValueTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.GroupStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.LambdaMapStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.GroupSideEffectStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.ProfileStep;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * An interface for common functionality of {@link GroupStep} and {@link GroupSideEffectStep}.
+ */
+public interface Grouping<S, K, V> {
+
+    /**
+     * Determines if the provided traversal is equal to the key traversal that the {@code Grouping} has.
+     */
+    public Traversal.Admin<S, K> getKeyTraversal();
+
+    /**
+     * Determines if the provided traversal is equal to the value traversal that the {@code Grouping} has.
+     */
+    public Traversal.Admin<S, V> getValueTraversal();
+
+    /**
+     * Determines the first (non-local) barrier step in the provided traversal. This method is used by {@link GroupStep}
+     * and {@link GroupSideEffectStep} to ultimately determine the reducing bi-operator.
+     *
+     * @param traversal The traversal to inspect.
+     * @return The first non-local barrier step or {@code null} if no such step was found.
+     */
+    public default Barrier determineBarrierStep(final Traversal.Admin<S, V> traversal) {
+        final List<Step> steps = traversal.getSteps();
+        for (int ix = 0; ix < steps.size(); ix++) {
+            final Step step = steps.get(ix);
+            if (step instanceof Barrier && !(step instanceof LocalBarrier)) {
+                final Barrier b = (Barrier) step;
+
+                // when profile() is enabled the step needs to be wrapped up with the barrier so that the timer on
+                // the ProfileStep is properly triggered
+                if (ix < steps.size() - 1 && steps.get(ix + 1) instanceof ProfileStep)
+                    return new ProfilingAware.ProfiledBarrier(b, (ProfileStep) steps.get(ix + 1));
+                else
+                    return b;
+            }
+        }
+        return null;
+    }
+
+    public default Traversal.Admin<S, V> convertValueTraversal(final Traversal.Admin<S, V> valueTraversal) {
+        if (valueTraversal instanceof ValueTraversal ||
+                valueTraversal instanceof TokenTraversal ||
+                valueTraversal instanceof IdentityTraversal ||
+                valueTraversal instanceof ColumnTraversal ||
+                valueTraversal.getStartStep() instanceof LambdaMapStep && ((LambdaMapStep) valueTraversal.getStartStep()).getMapFunction() instanceof FunctionTraverser) {
+            return (Traversal.Admin<S, V>) __.map(valueTraversal).fold();
+        } else
+            return valueTraversal;
+    }
+
+    public default Map<K, V> doFinalReduction(final Map<K, Object> map, final Traversal.Admin<S, V> valueTraversal) {
+        final Barrier barrierStep = determineBarrierStep(valueTraversal);
+        if (barrierStep != null) {
+            for (final K key : map.keySet()) {
+                valueTraversal.reset();
+                barrierStep.addBarrier(map.get(key));
+                if (valueTraversal.hasNext())
+                    map.put(key, valueTraversal.next());
+            }
+        }
+        return (Map<K, V>) map;
+    }
+}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/PathProcessor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/PathProcessor.java
index 8a5843a..f0b7e20 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/PathProcessor.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/PathProcessor.java
@@ -20,7 +20,7 @@
 
 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.ValueTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.lambda.IdentityTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.lambda.TokenTraversal;
 import org.apache.tinkerpop.gremlin.structure.T;
@@ -49,7 +49,7 @@
                 } else if (traversal instanceof TokenTraversal && ((TokenTraversal) traversal).getToken().equals(T.label)) {
                     if (max.compareTo(ElementRequirement.LABEL) < 0)
                         max = ElementRequirement.LABEL;
-                } else if (traversal instanceof ElementValueTraversal) {
+                } else if (traversal instanceof ValueTraversal) {
                     if (max.compareTo(ElementRequirement.PROPERTIES) < 0)
                         max = ElementRequirement.PROPERTIES;
                 } else {
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 36e7493..e2c0e17 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
@@ -109,26 +109,54 @@
 
     public enum Variable {START, END}
 
-    public default <S> S getScopeValue(final Pop pop, final String key, final Traverser.Admin<?> traverser) throws IllegalArgumentException {
-        final S o = getNullableScopeValue(pop, key, traverser);
-        if (null == o)
-            throw new IllegalArgumentException("Neither the sideEffects, map, nor path has a " + key + "-key: " + this);
-        return o;
+    /**
+     * Finds the object with the specified key for the current traverser and throws an exception if the key cannot
+     * be found.
+     *
+     * @throws KeyNotFoundException if the key does not exist
+     */
+    public default <S> S getScopeValue(final Pop pop, final Object key, final Traverser.Admin<?> traverser) throws KeyNotFoundException {
+        final Object object = traverser.get();
+        if (object instanceof Map && ((Map) object).containsKey(key))
+            return (S) ((Map) object).get(key);
+
+        if (key instanceof String) {
+            final String k = (String) key;
+            if (traverser.getSideEffects().exists(k))
+                return traverser.getSideEffects().get(k);
+
+            final Path path = traverser.path();
+            if (path.hasLabel(k))
+                return null == pop ? path.get(k) : path.get(pop, k);
+        }
+
+        throw new KeyNotFoundException(key, this);
     }
 
+    /**
+     * Calls {@link #getScopeValue(Pop, Object, Traverser.Admin)} but throws an unchecked {@code IllegalStateException}
+     * if the key cannot be found.
+     */
+    public default <S> S getSafeScopeValue(final Pop pop, final Object key, final Traverser.Admin<?> traverser) {
+        try {
+            return getScopeValue(pop, key, traverser);
+        } catch (KeyNotFoundException nfe) {
+            throw new IllegalArgumentException(nfe.getMessage(), nfe);
+        }
+    }
+
+    /**
+     * Calls {@link #getScopeValue(Pop, Object, Traverser.Admin)} and returns {@code null} if the key is not found.
+     * Use this method with caution as {@code null} has one of two meanings as a return value. It could be that the
+     * key was found and its value was {@code null} or it might mean that the key was not found and {@code null} was
+     * simply returned.
+     */
     public default <S> S getNullableScopeValue(final Pop pop, final String key, final Traverser.Admin<?> traverser) {
-        final Object object = traverser.get();
-        if (object instanceof Map && ((Map<String, S>) object).containsKey(key))
-            return ((Map<String, S>) object).get(key);
-
-        if (traverser.getSideEffects().exists(key))
-            return traverser.getSideEffects().get(key);
-
-        final Path path = traverser.path();
-        if (path.hasLabel(key))
-            return path.get(pop, key);
-
-        return null;
+        try {
+            return getScopeValue(pop, key, traverser);
+        } catch (KeyNotFoundException nfe) {
+            return null;
+        }
     }
 
     /**
@@ -137,4 +165,24 @@
      * @return the accessed labels of the scoping step
      */
     public Set<String> getScopeKeys();
+
+    public static class KeyNotFoundException extends Exception {
+
+        private final Object key;
+        private final Scoping step;
+
+        public KeyNotFoundException(final Object key, final Scoping current) {
+            super("Neither the map, sideEffects, nor path has a " + key + "-key: " + current);
+            this.key = key;
+            this.step = current;
+        }
+
+        public Object getKey() {
+            return key;
+        }
+
+        public Scoping getStep() {
+            return step;
+        }
+    }
 }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/Seedable.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/Seedable.java
new file mode 100644
index 0000000..29d1cb5
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/Seedable.java
@@ -0,0 +1,32 @@
+/*
+ * 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;
+
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SeedStrategy;
+
+/**
+ * An interface implemented by steps that have some form of {@code Random} usage that can be configured by way of a
+ * {@code seed} to allow for deterministic behavior of the step.
+ *
+ * @see SeedStrategy
+ */
+public interface Seedable {
+
+    public void resetSeed(final long seed);
+}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/TraversalParent.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/TraversalParent.java
index 10df950..695d297 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/TraversalParent.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/TraversalParent.java
@@ -20,7 +20,6 @@
 
 import org.apache.tinkerpop.gremlin.process.traversal.Step;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.EmptyStep;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
 
 import java.util.Collections;
@@ -57,6 +56,10 @@
         throw new IllegalStateException("This traversal parent does not support the removal of global traversals: " + this.getClass().getCanonicalName());
     }
 
+    public default void replaceLocalChild(final Traversal.Admin<?, ?> oldTraversal, final Traversal.Admin<?, ?> newTraversal) {
+        throw new IllegalStateException("This traversal parent does not support the replacement of local traversals: " + this.getClass().getCanonicalName());
+    }
+
     public default Set<TraverserRequirement> getSelfAndChildRequirements(final TraverserRequirement... selfRequirements) {
         final Set<TraverserRequirement> requirements = EnumSet.noneOf(TraverserRequirement.class);
         Collections.addAll(requirements, selfRequirements);
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 d92ce2d..361ed54 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
@@ -18,15 +18,12 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.step.branch;
 
-import org.apache.tinkerpop.gremlin.process.traversal.P;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import org.apache.tinkerpop.gremlin.process.traversal.lambda.PredicateTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.step.Barrier;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent;
-import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.IdentityStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.ComputerAwareStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.ReducingBarrierStep;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
 import org.apache.tinkerpop.gremlin.process.traversal.util.FastNoSuchElementException;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
@@ -41,7 +38,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.function.Predicate;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -82,10 +78,7 @@
             }
             this.traversalOptions.add(Pair.with(pickOptionTraversal, traversalOption));
         }
-        // adding an IdentityStep acts as a placeholder when reducing barriers get in the way - see the
-        // standardAlgorithm() method for more information.
-        if (TraversalHelper.hasStepOfAssignableClass(ReducingBarrierStep.class, traversalOption))
-            traversalOption.addStep(0, new IdentityStep(traversalOption));
+
         traversalOption.addStep(new EndStep(traversalOption));
 
         if (!this.hasBarrier && !TraversalHelper.getStepsOfAssignableClassRecursively(Barrier.class, traversalOption).isEmpty())
@@ -117,13 +110,11 @@
                 // this block is ignored on the first pass through the while(true) giving the opportunity for
                 // the traversalOptions to be prepared. Iterate all of them and simply return the ones that yield
                 // results. applyCurrentTraverser() will have only injected the current traverser into the options
-                // that met the choice requirements.  Note that in addGlobalChildOption an IdentityStep was added to
-                // be a holder for that current traverser. That allows us to check that first step for an injected
-                // traverser as part of the condition for using that traversal option in the output. This is necessary
-                // because barriers like fold(), max(), etc. will always return true for hasNext() even if a traverser
-                // was not seeded in applyCurrentTraverser().
+                // that met the choice requirements.
                 for (final Traversal.Admin<S, E> option : getGlobalChildren()) {
-                    if (option.getStartStep().hasNext() && option.hasNext())
+                    // checking hasStarts() first on the step in case there is a ReducingBarrierStep which will
+                    // always return true for hasNext()
+                    if (option.getStartStep().hasStarts() && option.hasNext())
                         return option.getEndStep();
                 }
             }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/CoinStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/CoinStep.java
index db2480d..a7d86cb 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/CoinStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/CoinStep.java
@@ -20,6 +20,7 @@
 
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+import org.apache.tinkerpop.gremlin.process.traversal.step.Seedable;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 
@@ -30,9 +31,9 @@
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class CoinStep<S> extends FilterStep<S> {
+public final class CoinStep<S> extends FilterStep<S> implements Seedable {
 
-    private static final Random RANDOM = new Random();
+    private final Random random = new Random();
     private final double probability;
 
     public CoinStep(final Traversal.Admin traversal, final double probability) {
@@ -41,19 +42,18 @@
     }
 
     @Override
+    public void resetSeed(final long seed) {
+        random.setSeed(seed);
+    }
+
+    @Override
     protected boolean filter(final Traverser.Admin<S> traverser) {
         long newBulk = 0l;
         if (traverser.bulk() < 100) {
             for (int i = 0; i < traverser.bulk(); i++) {
-                if (this.probability >= RANDOM.nextDouble())
+                if (this.probability >= random.nextDouble())
                     newBulk++;
             }
-        /*} else if (traverser.bulk() < 1000000) {
-            final double cumulative = RANDOM.nextDouble();
-            final long current = Double.valueOf(traverser.bulk() / 2.0d).longValue();
-            final double next = choose(traverser.bulk(), current) * Math.pow(this.probability,current) * Math.pow(1.0d - this.probability,traverser.bulk() - current);
-            if()
-            */
         } else {
             newBulk = Math.round(this.probability * traverser.bulk());
         }
@@ -76,22 +76,4 @@
     public Set<TraverserRequirement> getRequirements() {
         return Collections.singleton(TraverserRequirement.BULK);
     }
-
-    //////
-
-    private static double choose(long x, long y) {
-        if (y < 0 || y > x) return 0;
-        if (y > x / 2) {
-            // choose(n,k) == choose(n,n-k),
-            // so this could save a little effort
-            y = x - y;
-        }
-
-        double denominator = 1.0, numerator = 1.0;
-        for (long i = 1; i <= y; i++) {
-            denominator *= i;
-            numerator *= (x + 1 - i);
-        }
-        return numerator / denominator;
-    }
 }
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 08026c3..dd8235d 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
@@ -32,8 +32,10 @@
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
 import org.apache.tinkerpop.gremlin.process.traversal.util.FastNoSuchElementException;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil;
+import org.apache.tinkerpop.gremlin.structure.Property;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedFactory;
+import org.apache.tinkerpop.gremlin.structure.util.reference.ReferenceFactory;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -74,7 +76,7 @@
             return this.duplicateSet.add(TraversalUtil.applyNullable(traverser, this.dedupTraversal));
         } else {
             final List<Object> objects = new ArrayList<>(this.dedupLabels.size());
-            this.dedupLabels.forEach(label -> objects.add(TraversalUtil.applyNullable((S) this.getScopeValue(Pop.last, label, traverser), this.dedupTraversal)));
+            this.dedupLabels.forEach(label -> objects.add(TraversalUtil.applyNullable((S) this.getSafeScopeValue(Pop.last, label, traverser), this.dedupTraversal)));
             return this.duplicateSet.add(objects);
         }
     }
@@ -116,6 +118,12 @@
     }
 
     @Override
+    public void replaceLocalChild(final Traversal.Admin<?, ?> oldTraversal, final Traversal.Admin<?, ?> newTraversal) {
+        if (null != this.dedupTraversal && this.dedupTraversal.equals(oldTraversal))
+            this.dedupTraversal = this.integrateChild(newTraversal);
+    }
+
+    @Override
     public DedupGlobalStep<S> clone() {
         final DedupGlobalStep<S> clone = (DedupGlobalStep<S>) super.clone();
         clone.duplicateSet = new HashSet<>();
@@ -189,17 +197,30 @@
             if (null != this.dedupLabels) {
                 object = new ArrayList<>(this.dedupLabels.size());
                 for (final String label : this.dedupLabels) {
-                    ((List) object).add(TraversalUtil.applyNullable((S) this.getScopeValue(Pop.last, label, traverser), this.dedupTraversal));
+                    ((List) object).add(TraversalUtil.applyNullable((S) this.getSafeScopeValue(Pop.last, label, traverser), this.dedupTraversal));
                 }
             } else {
                 object = TraversalUtil.applyNullable(traverser, this.dedupTraversal);
             }
             if (!map.containsKey(object)) {
                 traverser.setBulk(1L);
-                if (this.onGraphComputer)
-                    traverser.set(DetachedFactory.detach(traverser.get(), true));
-                else
+
+                // DetachedProperty and DetachedVertexProperty both have a transient for the Host element. that causes
+                // trouble for olap which ends up requiring the Host later. can't change the transient without some
+                // consequences: (1) we break gryo formatting and io tests start failing (2) storing the element with
+                // the property has the potential to bloat detached Element instances as it basically stores that data
+                // twice. Not sure if it's smart to change that at least in 3.4.x and not without some considerable
+                // thought as to what might be major changes. To work around the problem we will detach properties as
+                // references so that the parent element goes with it. Also, given TINKERPOP-2318 property comparisons
+                // have changed in such a way that allows this to work properly
+                if (this.onGraphComputer) {
+                    if (traverser.get() instanceof Property)
+                        traverser.set(ReferenceFactory.detach(traverser.get()));
+                    else
+                        traverser.set(DetachedFactory.detach(traverser.get(), true));
+                } else {
                     traverser.set(traverser.get());
+                }
                 map.put(object, traverser);
             }
         }
@@ -225,7 +246,7 @@
     }
 
     @Override
-    public void setKeepLabels(Set<String> keepLabels) {
+    public void setKeepLabels(final Set<String> keepLabels) {
         this.keepLabels = new HashSet<>(keepLabels);
     }
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/PathFilterStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/PathFilterStep.java
index 72af0b1..8fa93bf 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/PathFilterStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/PathFilterStep.java
@@ -109,6 +109,13 @@
     }
 
     @Override
+    public void replaceLocalChild(final Traversal.Admin<?, ?> oldTraversal, final Traversal.Admin<?, ?> newTraversal) {
+        this.traversalRing.replaceTraversal(
+                (Traversal.Admin<Object, Object>) oldTraversal,
+                (Traversal.Admin<Object, Object>) newTraversal);
+    }
+
+    @Override
     public void reset() {
         super.reset();
         this.traversalRing.reset();
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/SampleGlobalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/SampleGlobalStep.java
index e4ca430..b342100 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/SampleGlobalStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/SampleGlobalStep.java
@@ -22,6 +22,7 @@
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import org.apache.tinkerpop.gremlin.process.traversal.lambda.ConstantTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.step.ByModulating;
+import org.apache.tinkerpop.gremlin.process.traversal.step.Seedable;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.CollectingBarrierStep;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.ProjectedTraverser;
@@ -38,11 +39,11 @@
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class SampleGlobalStep<S> extends CollectingBarrierStep<S> implements TraversalParent, ByModulating {
+public final class SampleGlobalStep<S> extends CollectingBarrierStep<S> implements TraversalParent, ByModulating, Seedable {
 
     private Traversal.Admin<S, Number> probabilityTraversal = new ConstantTraversal<>(1.0d);
     private final int amountToSample;
-    private static final Random RANDOM = new Random();
+    private final Random random = new Random();
 
     public SampleGlobalStep(final Traversal.Admin traversal, final int amountToSample) {
         super(traversal);
@@ -50,6 +51,11 @@
     }
 
     @Override
+    public void resetSeed(final long seed) {
+        random.setSeed(seed);
+    }
+
+    @Override
     public List<Traversal.Admin<S, Number>> getLocalChildren() {
         return Collections.singletonList(this.probabilityTraversal);
     }
@@ -60,6 +66,12 @@
     }
 
     @Override
+    public void replaceLocalChild(final Traversal.Admin<?, ?> oldTraversal, final Traversal.Admin<?, ?> newTraversal) {
+        if (null != this.probabilityTraversal && this.probabilityTraversal.equals(oldTraversal))
+            this.probabilityTraversal = this.integrateChild(newTraversal);
+    }
+
+    @Override
     public String toString() {
         return StringFactory.stepString(this, this.amountToSample, this.probabilityTraversal);
     }
@@ -92,7 +104,7 @@
                 if (sampleBulk < s.bulk()) {
                     final double currentWeight = ((ProjectedTraverser<S, Number>) s).getProjections().get(0).doubleValue();
                     for (int i = 0; i < (s.bulk() - sampleBulk); i++) {
-                        if (RANDOM.nextDouble() <= ((currentWeight / runningTotalWeight))) {
+                        if (random.nextDouble() <= ((currentWeight / runningTotalWeight))) {
                             final Traverser.Admin<S> split = s.split();
                             split.setBulk(1L);
                             sampledSet.add(split);
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 72dfebf..2ab3d9d 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
@@ -28,7 +28,6 @@
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
 import org.apache.tinkerpop.gremlin.process.traversal.util.ConnectiveP;
-import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalRing;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
@@ -79,7 +78,7 @@
         if (predicate instanceof ConnectiveP)
             ((ConnectiveP<Object>) predicate).getPredicates().forEach(p -> this.setPredicateValues(p, traverser, selectKeysIterator));
         else
-            predicate.setValue(TraversalUtil.applyNullable((S) this.getScopeValue(Pop.last, selectKeysIterator.next(), traverser), this.traversalRing.next()));
+            predicate.setValue(TraversalUtil.applyNullable((S) this.getSafeScopeValue(Pop.last, selectKeysIterator.next(), traverser), this.traversalRing.next()));
     }
 
     public Optional<P<?>> getPredicate() {
@@ -104,7 +103,7 @@
     protected boolean filter(final Traverser.Admin<S> traverser) {
         final Object value = null == this.startKey ?
                 TraversalUtil.applyNullable(traverser, this.traversalRing.next()) :
-                TraversalUtil.applyNullable((S) this.getScopeValue(Pop.last, this.startKey, traverser), this.traversalRing.next());
+                TraversalUtil.applyNullable((S) this.getSafeScopeValue(Pop.last, this.startKey, traverser), this.traversalRing.next());
         this.setPredicateValues(this.predicate, traverser, this.selectKeys.iterator());
         this.traversalRing.reset();
         return this.predicate.test(value);
@@ -169,4 +168,11 @@
     public void modulateBy(final Traversal.Admin<?, ?> traversal) throws UnsupportedOperationException {
         this.traversalRing.addTraversal(this.integrateChild(traversal));
     }
+
+    @Override
+    public void replaceLocalChild(final Traversal.Admin<?, ?> oldTraversal, final Traversal.Admin<?, ?> newTraversal) {
+        this.traversalRing.replaceTraversal(
+                (Traversal.Admin) oldTraversal,
+                (Traversal.Admin) newTraversal);
+    }
 }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WhereTraversalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WhereTraversalStep.java
index 384bbce..264575d 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WhereTraversalStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WhereTraversalStep.java
@@ -25,7 +25,7 @@
 import org.apache.tinkerpop.gremlin.process.traversal.step.PathProcessor;
 import org.apache.tinkerpop.gremlin.process.traversal.step.Scoping;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.MapStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.ScalarMapStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.StartStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.ProfileStep;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.ConnectiveStrategy;
@@ -149,7 +149,7 @@
 
     //////////////////////////////
 
-    public static class WhereStartStep<S> extends MapStep<S, Object> implements Scoping {
+    public static class WhereStartStep<S> extends ScalarMapStep<S, Object> implements Scoping {
 
         private String selectKey;
 
@@ -164,7 +164,7 @@
                 ((WhereEndStep) this.getTraversal().getEndStep()).processStartTraverser(traverser);
             else if (this.getTraversal().getEndStep() instanceof ProfileStep && this.getTraversal().getEndStep().getPreviousStep() instanceof WhereEndStep)     // TOTAL SUCKY HACK!
                 ((WhereEndStep) this.getTraversal().getEndStep().getPreviousStep()).processStartTraverser(traverser);
-            return null == this.selectKey ? traverser.get() : this.getScopeValue(Pop.last, this.selectKey, traverser);
+            return null == this.selectKey ? traverser.get() : this.getSafeScopeValue(Pop.last, this.selectKey, traverser);
         }
 
         @Override
@@ -199,7 +199,7 @@
 
         public void processStartTraverser(final Traverser.Admin traverser) {
             if (null != this.matchKey)
-                this.matchValue = this.getScopeValue(Pop.last, this.matchKey, traverser);
+                this.matchValue = this.getSafeScopeValue(Pop.last, this.matchKey, traverser);
         }
 
         @Override
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStartStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStartStep.java
index 63f6776..d2b81e9 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStartStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStartStep.java
@@ -105,16 +105,35 @@
         if (this.first) {
             this.first = false;
             final TraverserGenerator generator = this.getTraversal().getTraverserGenerator();
-            final Traverser.Admin traverser = generator.generate(1, (Step) this, 1); // a dead traverser to trigger the traversal
-            Vertex toVertex = (Vertex) this.parameters.get(traverser, TO, Collections::emptyList).get(0);
-            Vertex fromVertex = (Vertex) this.parameters.get(traverser, FROM, Collections::emptyList).get(0);
+
+            // a dead traverser to trigger the traversal
+            final Traverser.Admin traverser = generator.generate(1, (Step) this, 1);
+
+            final String edgeLabel = (String) this.parameters.get(traverser, T.label, () -> Edge.DEFAULT_LABEL).get(0);
+
+            // FROM/TO must be set and must be vertices
+            final Object theTo = this.parameters.get(traverser, TO, () -> null).get(0);
+            if (!(theTo instanceof Vertex))
+                throw new IllegalStateException(String.format(
+                        "addE(%s) could not find a Vertex for to() - encountered: %s", edgeLabel,
+                        null == theTo ? "null" : theTo.getClass().getSimpleName()));
+
+            final Object theFrom = this.parameters.get(traverser, FROM, () -> null).get(0);
+            if (!(theFrom instanceof Vertex))
+                throw new IllegalStateException(String.format(
+                        "addE(%s) could not find a Vertex for from() - encountered: %s", edgeLabel,
+                        null == theFrom ? "null" : theFrom.getClass().getSimpleName()));
+
+            Vertex toVertex = (Vertex) theTo;
+            Vertex fromVertex = (Vertex) theFrom;
+
             if (toVertex instanceof Attachable)
                 toVertex = ((Attachable<Vertex>) toVertex)
                         .attach(Attachable.Method.get(this.getTraversal().getGraph().orElse(EmptyGraph.instance())));
             if (fromVertex instanceof Attachable)
                 fromVertex = ((Attachable<Vertex>) fromVertex)
                         .attach(Attachable.Method.get(this.getTraversal().getGraph().orElse(EmptyGraph.instance())));
-            final String edgeLabel = (String) this.parameters.get(traverser, T.label, () -> Edge.DEFAULT_LABEL).get(0);
+
             final Edge edge = fromVertex.addEdge(edgeLabel, toVertex, this.parameters.getKeyValues(traverser, TO, FROM, T.label));
             if (callbackRegistry != null && !callbackRegistry.getCallbacks().isEmpty()) {
                 final EventStrategy eventStrategy = getTraversal().getStrategies().getStrategy(EventStrategy.class).get();
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java
index 55d0866..1bf5d4a 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java
@@ -45,7 +45,7 @@
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
-public class AddEdgeStep<S> extends MapStep<S, Edge>
+public class AddEdgeStep<S> extends ScalarMapStep<S, Edge>
         implements Mutating<Event.EdgeAddedEvent>, TraversalParent, Scoping, FromToModulating {
 
     private static final String FROM = Graph.Hidden.hide("from");
@@ -96,15 +96,28 @@
 
     @Override
     protected Edge map(final Traverser.Admin<S> traverser) {
-        Vertex toVertex = this.parameters.get(traverser, TO, () -> (Vertex) traverser.get()).get(0);
-        Vertex fromVertex = this.parameters.get(traverser, FROM, () -> (Vertex) traverser.get()).get(0);
+        final String edgeLabel = this.parameters.get(traverser, T.label, () -> Edge.DEFAULT_LABEL).get(0);
+        final Object theTo = this.parameters.get(traverser, TO, traverser::get).get(0);
+        if (!(theTo instanceof Vertex))
+            throw new IllegalStateException(String.format(
+                    "addE(%s) could not find a Vertex for to() - encountered: %s", edgeLabel,
+                    null == theTo ? "null" : theTo.getClass().getSimpleName()));
+
+        final Object theFrom = this.parameters.get(traverser, FROM, traverser::get).get(0);
+        if (!(theFrom instanceof Vertex))
+            throw new IllegalStateException(String.format(
+                    "addE(%s) could not find a Vertex for from() - encountered: %s", edgeLabel,
+                    null == theFrom ? "null" : theFrom.getClass().getSimpleName()));
+
+        Vertex toVertex = (Vertex) theTo;
+        Vertex fromVertex = (Vertex) theFrom;
+
         if (toVertex instanceof Attachable)
             toVertex = ((Attachable<Vertex>) toVertex)
                     .attach(Attachable.Method.get(this.getTraversal().getGraph().orElse(EmptyGraph.instance())));
         if (fromVertex instanceof Attachable)
             fromVertex = ((Attachable<Vertex>) fromVertex)
                     .attach(Attachable.Method.get(this.getTraversal().getGraph().orElse(EmptyGraph.instance())));
-        final String edgeLabel = this.parameters.get(traverser, T.label, () -> Edge.DEFAULT_LABEL).get(0);
 
         final Edge edge = fromVertex.addEdge(edgeLabel, toVertex, this.parameters.getKeyValues(traverser, TO, FROM, T.label));
         if (callbackRegistry != null && !callbackRegistry.getCallbacks().isEmpty()) {
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStartStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStartStep.java
index 2182921..54ce962 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStartStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStartStep.java
@@ -53,12 +53,12 @@
 
     public AddVertexStartStep(final Traversal.Admin traversal, final String label) {
         super(traversal);
-        this.parameters.set(this, T.label, label);
+        this.parameters.set(this, T.label, null == label ? Vertex.DEFAULT_LABEL : label);
     }
 
     public AddVertexStartStep(final Traversal.Admin traversal, final Traversal<?, String> vertexLabelTraversal) {
         super(traversal);
-        this.parameters.set(this, T.label, vertexLabelTraversal);
+        this.parameters.set(this, T.label, null == vertexLabelTraversal ? Vertex.DEFAULT_LABEL : vertexLabelTraversal);
     }
 
     @Override
@@ -78,7 +78,20 @@
 
     @Override
     public void configure(final Object... keyValues) {
-        this.parameters.set(this, keyValues);
+        if (keyValues[0] == T.label && this.parameters.contains(T.label)) {
+            if (this.parameters.contains(T.label, Vertex.DEFAULT_LABEL)) {
+                this.parameters.remove(T.label);
+                this.parameters.set(this, keyValues);
+            } else {
+                throw new IllegalArgumentException(String.format("Vertex T.label has already been set to [%s] and cannot be overridden with [%s]",
+                        this.parameters.getRaw().get(T.label).get(0), keyValues[1]));
+            }
+        } else if (keyValues[0] == T.id && this.parameters.contains(T.id)) {
+            throw new IllegalArgumentException(String.format("Vertex T.id has already been set to [%s] and cannot be overridden with [%s]",
+                    this.parameters.getRaw().get(T.id).get(0), keyValues[1]));
+        } else {
+            this.parameters.set(this, keyValues);
+        }
     }
 
     @Override
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java
index a609422..343c44b 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java
@@ -40,7 +40,7 @@
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
-public class AddVertexStep<S> extends MapStep<S, Vertex>
+public class AddVertexStep<S> extends ScalarMapStep<S, Vertex>
         implements Mutating<Event.VertexAddedEvent>, TraversalParent, Scoping {
 
     private Parameters parameters = new Parameters();
@@ -48,12 +48,12 @@
 
     public AddVertexStep(final Traversal.Admin traversal, final String label) {
         super(traversal);
-        this.parameters.set(this, T.label, label);
+        this.parameters.set(this, T.label, null == label ? Vertex.DEFAULT_LABEL : label);
     }
 
     public AddVertexStep(final Traversal.Admin traversal, final Traversal.Admin<S,String> vertexLabelTraversal) {
         super(traversal);
-        this.parameters.set(this, T.label, vertexLabelTraversal);
+        this.parameters.set(this, T.label, null == vertexLabelTraversal ? Vertex.DEFAULT_LABEL : vertexLabelTraversal);
     }
 
     @Override
@@ -73,7 +73,20 @@
 
     @Override
     public void configure(final Object... keyValues) {
-        this.parameters.set(this, keyValues);
+        if (keyValues[0] == T.label && this.parameters.contains(T.label)) {
+            if (this.parameters.contains(T.label, Vertex.DEFAULT_LABEL)) {
+                this.parameters.remove(T.label);
+                this.parameters.set(this, keyValues);
+            } else {
+                throw new IllegalArgumentException(String.format("Vertex T.label has already been set to [%s] and cannot be overridden with [%s]",
+                        this.parameters.getRaw().get(T.label).get(0), keyValues[1]));
+            }
+        } else if (keyValues[0] == T.id && this.parameters.contains(T.id)) {
+            throw new IllegalArgumentException(String.format("Vertex T.id has already been set to [%s] and cannot be overridden with [%s]",
+                    this.parameters.getRaw().get(T.id).get(0), keyValues[1]));
+        } else {
+            this.parameters.set(this, keyValues);
+        }
     }
 
     @Override
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConstantStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConstantStep.java
index 749de31..9434cc3 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConstantStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConstantStep.java
@@ -27,7 +27,7 @@
 import java.util.Objects;
 import java.util.Set;
 
-public class ConstantStep<S, E> extends MapStep<S, E> {
+public class ConstantStep<S, E> extends ScalarMapStep<S, E> {
 
     private final E constant;
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CountLocalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CountLocalStep.java
index 87b699d..25e75e4 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CountLocalStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CountLocalStep.java
@@ -32,7 +32,7 @@
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  * @author Daniel Kuppitz (http://gremlin.guru)
  */
-public final class CountLocalStep<S> extends MapStep<S, Long> {
+public final class CountLocalStep<S> extends ScalarMapStep<S, Long> {
 
     public CountLocalStep(final Traversal.Admin traversal) {
         super(traversal);
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DedupLocalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DedupLocalStep.java
index 59c66c7..4d75270 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DedupLocalStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DedupLocalStep.java
@@ -29,7 +29,7 @@
 /**
  * @author Daniel Kuppitz (http://gremlin.guru)
  */
-public final class DedupLocalStep<E, S extends Iterable<E>> extends MapStep<S, Set<E>> {
+public final class DedupLocalStep<E, S extends Iterable<E>> extends ScalarMapStep<S, Set<E>> {
 
     public DedupLocalStep(final Traversal.Admin traversal) {
         super(traversal);
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/EdgeOtherVertexStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/EdgeOtherVertexStep.java
index a53dd50..0d151d0 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/EdgeOtherVertexStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/EdgeOtherVertexStep.java
@@ -34,7 +34,7 @@
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public class EdgeOtherVertexStep extends MapStep<Edge, Vertex> implements Configuring {
+public class EdgeOtherVertexStep extends ScalarMapStep<Edge, Vertex> implements Configuring {
     protected Parameters parameters = new Parameters();
 
     public EdgeOtherVertexStep(final Traversal.Admin traversal) {
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ElementMapStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ElementMapStep.java
index 2f1db43..1654aa1 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ElementMapStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ElementMapStep.java
@@ -45,7 +45,7 @@
  * @author Daniel Kuppitz (http://gremlin.guru)
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
-public class ElementMapStep<K,E> extends MapStep<Element, Map<K, E>> implements TraversalParent, GraphComputing {
+public class ElementMapStep<K,E> extends ScalarMapStep<Element, Map<K, E>> implements TraversalParent, GraphComputing {
 
     protected final String[] propertyKeys;
     private boolean onGraphComputer = false;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroupCountStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroupCountStep.java
index a0c02fd..e679240 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroupCountStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroupCountStep.java
@@ -79,6 +79,12 @@
     }
 
     @Override
+    public void replaceLocalChild(final Traversal.Admin<?, ?> oldTraversal, final Traversal.Admin<?, ?> newTraversal) {
+        if (null != this.keyTraversal && this.keyTraversal.equals(oldTraversal))
+            this.keyTraversal = this.integrateChild(newTraversal);
+    }
+
+    @Override
     public GroupCountStep<S, E> clone() {
         final GroupCountStep<S, E> clone = (GroupCountStep<S, E>) super.clone();
         if (null != this.keyTraversal)
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroupStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroupStep.java
index fb0bf3a..2213b2e 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroupStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroupStep.java
@@ -20,21 +20,14 @@
 package org.apache.tinkerpop.gremlin.process.traversal.step.map;
 
 import org.apache.tinkerpop.gremlin.process.traversal.Operator;
-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.dsl.graph.__;
-import org.apache.tinkerpop.gremlin.process.traversal.lambda.ColumnTraversal;
-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.TokenTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.step.Grouping;
 import org.apache.tinkerpop.gremlin.process.traversal.step.ProfilingAware;
 import org.apache.tinkerpop.gremlin.process.traversal.step.ByModulating;
-import org.apache.tinkerpop.gremlin.process.traversal.step.LocalBarrier;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
 import org.apache.tinkerpop.gremlin.process.traversal.step.Barrier;
-import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.GroupSideEffectStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.ProfileStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.ReducingBarrierStep;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
@@ -53,7 +46,8 @@
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class GroupStep<S, K, V> extends ReducingBarrierStep<S, Map<K, V>> implements ByModulating, TraversalParent, ProfilingAware {
+public final class GroupStep<S, K, V> extends ReducingBarrierStep<S, Map<K, V>>
+        implements ByModulating, TraversalParent, ProfilingAware, Grouping<S, K, V> {
 
     private char state = 'k';
     private Traversal.Admin<S, K> keyTraversal;
@@ -70,31 +64,6 @@
     }
 
     /**
-     * Determines the first (non-local) barrier step in the provided traversal. This method is used by {@link GroupStep}
-     * and {@link GroupSideEffectStep} to ultimately determine the reducing bi-operator.
-     *
-     * @param traversal The traversal to inspect.
-     * @return The first non-local barrier step or {@code null} if no such step was found.
-     */
-    public static <S, V> Barrier determineBarrierStep(final Traversal.Admin<S, V> traversal) {
-        final List<Step> steps = traversal.getSteps();
-        for (int ix = 0; ix < steps.size(); ix++) {
-            final Step step = steps.get(ix);
-            if (step instanceof Barrier && !(step instanceof LocalBarrier)) {
-                final Barrier b = (Barrier) step;
-
-                // when profile() is enabled the step needs to be wrapped up with the barrier so that the timer on
-                // the ProfileStep is properly triggered
-                if (ix < steps.size() - 1 && steps.get(ix + 1) instanceof ProfileStep)
-                    return new ProfilingAware.ProfiledBarrier(b, (ProfileStep) steps.get(ix + 1));
-                else
-                    return b;
-            }
-        }
-        return null;
-    }
-
-    /**
      * Reset the {@link Barrier} on the step to be wrapped in a {@link ProfiledBarrier} which can properly start/stop
      * the timer on the associated {@link ProfileStep}.
      */
@@ -104,14 +73,28 @@
     }
 
     @Override
+    public Traversal.Admin<S, K> getKeyTraversal() {
+        return this.keyTraversal;
+    }
+
+    @Override
+    public Traversal.Admin<S, V> getValueTraversal() {
+        return this.valueTraversal;
+    }
+
+    private void setValueTraversal(final Traversal.Admin kvTraversal) {
+        this.valueTraversal = this.integrateChild(convertValueTraversal(kvTraversal));
+        this.barrierStep = determineBarrierStep(this.valueTraversal);
+        this.setReducingBiOperator(new GroupBiOperator<>(null == this.barrierStep ? Operator.assign : this.barrierStep.getMemoryComputeKey().getReducer()));
+    }
+
+    @Override
     public void modulateBy(final Traversal.Admin<?, ?> kvTraversal) {
         if ('k' == this.state) {
             this.keyTraversal = this.integrateChild(kvTraversal);
             this.state = 'v';
         } else if ('v' == this.state) {
-            this.valueTraversal = this.integrateChild(convertValueTraversal(kvTraversal));
-            this.barrierStep = determineBarrierStep(this.valueTraversal);
-            this.setReducingBiOperator(new GroupBiOperator<>(null == this.barrierStep ? Operator.assign : this.barrierStep.getMemoryComputeKey().getReducer()));
+            this.setValueTraversal(kvTraversal);
             this.state = 'x';
         } else {
             throw new IllegalStateException("The key and value traversals for group()-step have already been set: " + this);
@@ -119,6 +102,14 @@
     }
 
     @Override
+    public void replaceLocalChild(final Traversal.Admin<?, ?> oldTraversal, final Traversal.Admin<?, ?> newTraversal) {
+        if (null != this.keyTraversal && this.keyTraversal.equals(oldTraversal))
+            this.keyTraversal = this.integrateChild(newTraversal);
+        else if (null != this.valueTraversal && this.valueTraversal.equals(oldTraversal))
+            this.setValueTraversal(newTraversal);
+    }
+
+    @Override
     public Map<K, V> projectTraverser(final Traverser.Admin<S> traverser) {
         final Map<K, V> map = new HashMap<>(1);
         this.valueTraversal.reset();
@@ -187,7 +178,7 @@
 
     @Override
     public Map<K, V> generateFinalResult(final Map<K, V> object) {
-        return GroupStep.doFinalReduction((Map<K, Object>) object, this.valueTraversal);
+        return doFinalReduction((Map<K, Object>) object, this.valueTraversal);
     }
 
     ///////////////////////
@@ -218,31 +209,4 @@
             return mapA;
         }
     }
-
-
-    ///////////////////////
-
-    public static <S, E> Traversal.Admin<S, E> convertValueTraversal(final Traversal.Admin<S, E> valueTraversal) {
-        if (valueTraversal instanceof ElementValueTraversal ||
-                valueTraversal instanceof TokenTraversal ||
-                valueTraversal instanceof IdentityTraversal ||
-                valueTraversal instanceof ColumnTraversal ||
-                valueTraversal.getStartStep() instanceof LambdaMapStep && ((LambdaMapStep) valueTraversal.getStartStep()).getMapFunction() instanceof FunctionTraverser) {
-            return (Traversal.Admin<S, E>) __.map(valueTraversal).fold();
-        } else
-            return valueTraversal;
-    }
-
-    public static <K, V> Map<K, V> doFinalReduction(final Map<K, Object> map, final Traversal.Admin<?, V> valueTraversal) {
-        final Barrier barrierStep = determineBarrierStep(valueTraversal);
-        if (barrierStep != null) {
-            for (final K key : map.keySet()) {
-                valueTraversal.reset();
-                barrierStep.addBarrier(map.get(key));
-                if (valueTraversal.hasNext())
-                    map.put(key, valueTraversal.next());
-            }
-        }
-        return (Map<K, V>) map;
-    }
 }
\ No newline at end of file
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IdStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IdStep.java
index 018c91e..c5eb7c4 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IdStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IdStep.java
@@ -29,7 +29,7 @@
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class IdStep<S extends Element> extends MapStep<S, Object> {
+public final class IdStep<S extends Element> extends ScalarMapStep<S, Object> {
 
     public IdStep(final Traversal.Admin traversal) {
         super(traversal);
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IndexStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IndexStep.java
index b903c15..314e751 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IndexStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IndexStep.java
@@ -40,7 +40,7 @@
 /**
  * @author Daniel Kuppitz (http://gremlin.guru)
  */
-public class IndexStep<S, E> extends MapStep<S, E> implements TraversalParent, Configuring {
+public class IndexStep<S, E> extends ScalarMapStep<S, E> implements TraversalParent, Configuring {
 
     private final static IllegalArgumentException INVALID_CONFIGURATION_EXCEPTION =
             new IllegalArgumentException("WithOptions.indexer requires a single Integer argument (possible " + "" +
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LabelStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LabelStep.java
index 2b2313f..060dc68 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LabelStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LabelStep.java
@@ -29,7 +29,7 @@
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class LabelStep<S extends Element> extends MapStep<S, String> {
+public final class LabelStep<S extends Element> extends ScalarMapStep<S, String> {
 
     public LabelStep(final Traversal.Admin traversal) {
         super(traversal);
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LambdaMapStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LambdaMapStep.java
index b2024f8..ce6a1bd 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LambdaMapStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LambdaMapStep.java
@@ -28,7 +28,7 @@
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class LambdaMapStep<S, E> extends MapStep<S, E> implements LambdaHolder {
+public final class LambdaMapStep<S, E> extends ScalarMapStep<S, E> implements LambdaHolder {
 
     private final Function<Traverser<S>, E> function;
 
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
index 11d8729..c3d2ac8 100644
--- 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
@@ -24,7 +24,7 @@
 /**
  * @author Daniel Kuppitz (http://gremlin.guru)
  */
-public final class LoopsStep<S> extends MapStep<S, Integer> {
+public final class LoopsStep<S> extends ScalarMapStep<S, Integer> {
 
     private String loopName;
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapStep.java
index 03e544e..5d5103c 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapStep.java
@@ -18,26 +18,23 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.step.map;
 
+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.step.util.AbstractStep;
 
 /**
+ * A marker base class that designates an extending {@link Step} as a "Map" step which will transform the object of one
+ * {@link Traverser} into another. In many cases, it may be easier to simply extend from {@link ScalarMapStep} which
+ * has a straightforward implementation pattern.
+ *
  * @author Marko A. Rodriguez (http://markorodriguez.com)
+ * @author Stephen Mallette (http://stephen.genoprime.com)
  */
 public abstract class MapStep<S, E> extends AbstractStep<S, E> {
 
     public MapStep(final Traversal.Admin traversal) {
         super(traversal);
     }
-
-    @Override
-    protected Traverser.Admin<E> processNextStart() {
-        final Traverser.Admin<S> traverser = this.starts.next();
-        return traverser.split(this.map(traverser), this);
-    }
-
-    protected abstract E map(final Traverser.Admin<S> traverser);
-
 }
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MathStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MathStep.java
index 7a483a1..149f67a 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MathStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MathStep.java
@@ -45,7 +45,7 @@
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class MathStep<S> extends MapStep<S, Double> implements ByModulating, TraversalParent, Scoping, PathProcessor {
+public final class MathStep<S> extends ScalarMapStep<S, Double> implements ByModulating, TraversalParent, Scoping, PathProcessor {
 
     private static final String CURRENT = "_";
     private final String equation;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MaxLocalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MaxLocalStep.java
index 3ad326f..187ad39 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MaxLocalStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MaxLocalStep.java
@@ -33,7 +33,7 @@
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  * @author Daniel Kuppitz (http://gremlin.guru)
  */
-public final class MaxLocalStep<E extends Comparable, S extends Iterable<E>> extends MapStep<S, E> {
+public final class MaxLocalStep<E extends Comparable, S extends Iterable<E>> extends ScalarMapStep<S, E> {
 
     public MaxLocalStep(final Traversal.Admin traversal) {
         super(traversal);
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MeanLocalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MeanLocalStep.java
index 91447fd..5ffb1a6 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MeanLocalStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MeanLocalStep.java
@@ -32,7 +32,7 @@
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  * @author Daniel Kuppitz (http://gremlin.guru)
  */
-public final class MeanLocalStep<E extends Number, S extends Iterable<E>> extends MapStep<S, Number> {
+public final class MeanLocalStep<E extends Number, S extends Iterable<E>> extends ScalarMapStep<S, Number> {
 
     public MeanLocalStep(final Traversal.Admin traversal) {
         super(traversal);
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MinLocalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MinLocalStep.java
index 4139a7d..3bdb969 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MinLocalStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MinLocalStep.java
@@ -33,7 +33,7 @@
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  * @author Daniel Kuppitz (http://gremlin.guru)
  */
-public final class MinLocalStep<E extends Comparable, S extends Iterable<E>> extends MapStep<S, E> {
+public final class MinLocalStep<E extends Comparable, S extends Iterable<E>> extends ScalarMapStep<S, E> {
 
     public MinLocalStep(final Traversal.Admin traversal) {
         super(traversal);
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderGlobalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderGlobalStep.java
index cc7cec6..a7f7892 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderGlobalStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderGlobalStep.java
@@ -25,6 +25,7 @@
 import org.apache.tinkerpop.gremlin.process.traversal.lambda.IdentityTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.step.ByModulating;
 import org.apache.tinkerpop.gremlin.process.traversal.step.ComparatorHolder;
+import org.apache.tinkerpop.gremlin.process.traversal.step.Seedable;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.CollectingBarrierStep;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.ProjectedTraverser;
@@ -41,6 +42,7 @@
 import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Random;
 import java.util.Set;
 import java.util.function.BinaryOperator;
 import java.util.stream.Collectors;
@@ -48,22 +50,28 @@
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class OrderGlobalStep<S, C extends Comparable> extends CollectingBarrierStep<S> implements ComparatorHolder<S, C>, TraversalParent, ByModulating {
+public final class OrderGlobalStep<S, C extends Comparable> extends CollectingBarrierStep<S> implements ComparatorHolder<S, C>, TraversalParent, ByModulating, Seedable {
 
     private List<Pair<Traversal.Admin<S, C>, Comparator<C>>> comparators = new ArrayList<>();
     private MultiComparator<C> multiComparator = null;
     private long limit = Long.MAX_VALUE;
+    private final Random random = new Random();
 
     public OrderGlobalStep(final Traversal.Admin traversal) {
         super(traversal);
     }
 
     @Override
+    public void resetSeed(long seed) {
+        this.random.setSeed(seed);
+    }
+
+    @Override
     public void barrierConsumer(final TraverserSet<S> traverserSet) {
         if (null == this.multiComparator) this.multiComparator = this.createMultiComparator();
         //
         if (this.multiComparator.isShuffle())
-            traverserSet.shuffle();
+            traverserSet.shuffle(random);
         else
             traverserSet.sort((Comparator) this.multiComparator);
     }
@@ -99,6 +107,19 @@
     }
 
     @Override
+    public void replaceLocalChild(final Traversal.Admin<?, ?> oldTraversal, final Traversal.Admin<?, ?> newTraversal) {
+        int i = 0;
+        for (final Pair<Traversal.Admin<S, C>, Comparator<C>> pair : this.comparators) {
+            final Traversal.Admin<S, C> traversal = pair.getValue0();
+            if (null != traversal && traversal.equals(oldTraversal)) {
+                this.comparators.set(i, Pair.with(this.integrateChild(newTraversal), pair.getValue1()));
+                break;
+            }
+            i++;
+        }
+    }
+
+    @Override
     public List<Pair<Traversal.Admin<S, C>, Comparator<C>>> getComparators() {
         return this.comparators.isEmpty() ? Collections.singletonList(new Pair<>(new IdentityTraversal(), (Comparator) Order.asc)) : Collections.unmodifiableList(this.comparators);
     }
@@ -146,15 +167,19 @@
     @Override
     public MemoryComputeKey<TraverserSet<S>> getMemoryComputeKey() {
         if (null == this.multiComparator) this.multiComparator = this.createMultiComparator();
-        return MemoryComputeKey.of(this.getId(), new OrderBiOperator<>(this.limit, this.multiComparator), false, true);
+        return MemoryComputeKey.of(this.getId(), new OrderBiOperator<>(this.limit, this.multiComparator, this.random), false, true);
     }
 
     private final ProjectedTraverser<S, Object> createProjectedTraverser(final Traverser.Admin<S> traverser) {
+        // this was ProjectedTraverser<S, C> but the projection may not be C in the case of a lambda where a
+        // Comparable may not be expected but rather an object that can be compared in any way given a lambda.
+        // not sure why this is suddenly an issue but Intellij would not let certain tests pass without this
+        // adjustment here.
         final List<Object> projections = new ArrayList<>(this.comparators.size());
         for (final Pair<Traversal.Admin<S, C>, Comparator<C>> pair : this.comparators) {
             projections.add(TraversalUtil.apply(traverser, pair.getValue0()));
         }
-        return new ProjectedTraverser<>(traverser, projections);
+        return new ProjectedTraverser(traverser, projections);
     }
 
     private final MultiComparator<C> createMultiComparator() {
@@ -171,14 +196,16 @@
 
         private long limit;
         private MultiComparator comparator;
+        private Random random;
 
         private OrderBiOperator() {
             // for serializers that need a no-arg constructor
         }
 
-        public OrderBiOperator(final long limit, final MultiComparator multiComparator) {
+        public OrderBiOperator(final long limit, final MultiComparator multiComparator, final Random random) {
             this.limit = limit;
             this.comparator = multiComparator;
+            this.random = random;
         }
 
         @Override
@@ -186,7 +213,7 @@
             setA.addAll(setB);
             if (this.limit != -1 && setA.bulkSize() > this.limit) {
                 if (this.comparator.isShuffle())
-                    setA.shuffle();
+                    setA.shuffle(random);
                 else
                     setA.sort(this.comparator);
                 long counter = 0L;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderLocalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderLocalStep.java
index 95cb6db..eb3a5f8 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderLocalStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderLocalStep.java
@@ -24,6 +24,7 @@
 import org.apache.tinkerpop.gremlin.process.traversal.lambda.IdentityTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.step.ByModulating;
 import org.apache.tinkerpop.gremlin.process.traversal.step.ComparatorHolder;
+import org.apache.tinkerpop.gremlin.process.traversal.step.Seedable;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
@@ -37,30 +38,37 @@
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Random;
 import java.util.Set;
 import java.util.stream.Collectors;
 
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class OrderLocalStep<S, C extends Comparable> extends MapStep<S, S> implements ComparatorHolder<S, C>, ByModulating, TraversalParent {
+public final class OrderLocalStep<S, C extends Comparable> extends ScalarMapStep<S, S> implements ComparatorHolder<S, C>, ByModulating, TraversalParent, Seedable {
 
     private List<Pair<Traversal.Admin<S, C>, Comparator<C>>> comparators = new ArrayList<>();
     private ChainedComparator<S, C> chainedComparator = null;
+    private final Random random = new Random();
 
     public OrderLocalStep(final Traversal.Admin traversal) {
         super(traversal);
     }
 
     @Override
+    public void resetSeed(long seed) {
+        this.random.setSeed(seed);
+    }
+
+    @Override
     protected S map(final Traverser.Admin<S> traverser) {
         if (null == this.chainedComparator)
             this.chainedComparator = new ChainedComparator<>(false, this.comparators);
         final S start = traverser.get();
         if (start instanceof Collection)
-            return (S) OrderLocalStep.sortCollection((Collection) start, this.chainedComparator);
+            return (S) sortCollection((Collection) start, this.chainedComparator);
         else if (start instanceof Map)
-            return (S) OrderLocalStep.sortMap((Map) start, this.chainedComparator);
+            return (S) sortMap((Map) start, this.chainedComparator);
         else
             return start;
     }
@@ -81,6 +89,19 @@
     }
 
     @Override
+    public void replaceLocalChild(final Traversal.Admin<?, ?> oldTraversal, final Traversal.Admin<?, ?> newTraversal) {
+        int i = 0;
+        for (final Pair<Traversal.Admin<S, C>, Comparator<C>> pair : this.comparators) {
+            final Traversal.Admin<S, C> traversal = pair.getValue0();
+            if (null != traversal && traversal.equals(oldTraversal)) {
+                this.comparators.set(i, Pair.with(this.integrateChild(newTraversal), pair.getValue1()));
+                break;
+            }
+            i++;
+        }
+    }
+
+    @Override
     public List<Pair<Traversal.Admin<S, C>, Comparator<C>>> getComparators() {
         return this.comparators.isEmpty() ? Collections.singletonList(new Pair<>(new IdentityTraversal(), (Comparator) Order.asc)) : Collections.unmodifiableList(this.comparators);
     }
@@ -129,10 +150,10 @@
 
     /////////////
 
-    private static final <A> List<A> sortCollection(final Collection<A> collection, final ChainedComparator comparator) {
+    private <A> List<A> sortCollection(final Collection<A> collection, final ChainedComparator comparator) {
         if (collection instanceof List) {
             if (comparator.isShuffle())
-                Collections.shuffle((List) collection);
+                Collections.shuffle((List) collection, random);
             else
                 Collections.sort((List) collection, comparator);
             return (List<A>) collection;
@@ -141,10 +162,10 @@
         }
     }
 
-    private static final <K, V> Map<K, V> sortMap(final Map<K, V> map, final ChainedComparator comparator) {
+    private <K, V> Map<K, V> sortMap(final Map<K, V> map, final ChainedComparator comparator) {
         final List<Map.Entry<K, V>> entries = new ArrayList<>(map.entrySet());
         if (comparator.isShuffle())
-            Collections.shuffle(entries);
+            Collections.shuffle(entries, random);
         else
             Collections.sort(entries, comparator);
         final LinkedHashMap<K, V> sortedMap = new LinkedHashMap<>();
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PathStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PathStep.java
index bf7572c..07c8d7d 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PathStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PathStep.java
@@ -38,7 +38,7 @@
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class PathStep<S> extends MapStep<S, Path> implements TraversalParent, PathProcessor, ByModulating, FromToModulating {
+public final class PathStep<S> extends ScalarMapStep<S, Path> implements TraversalParent, PathProcessor, ByModulating, FromToModulating {
 
     private TraversalRing<Object, Object> traversalRing;
     private Set<String> keepLabels;
@@ -99,6 +99,13 @@
     }
 
     @Override
+    public void replaceLocalChild(final Traversal.Admin<?, ?> oldTraversal, final Traversal.Admin<?, ?> newTraversal) {
+        this.traversalRing.replaceTraversal(
+                (Traversal.Admin<Object, Object>) oldTraversal,
+                (Traversal.Admin<Object, Object>) newTraversal);
+    }
+
+    @Override
     public String toString() {
         return StringFactory.stepString(this, this.traversalRing);
     }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProjectStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProjectStep.java
index 3ddd4a6..b97c8d6 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProjectStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProjectStep.java
@@ -37,7 +37,7 @@
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class ProjectStep<S, E> extends MapStep<S, Map<String, E>> implements TraversalParent, ByModulating {
+public final class ProjectStep<S, E> extends ScalarMapStep<S, Map<String, E>> implements TraversalParent, ByModulating {
 
     private final List<String> projectKeys;
     private TraversalRing<S, E> traversalRing;
@@ -97,6 +97,13 @@
         this.traversalRing.addTraversal(this.integrateChild(selectTraversal));
     }
 
+    @Override
+    public void replaceLocalChild(final Traversal.Admin<?, ?> oldTraversal, final Traversal.Admin<?, ?> newTraversal) {
+        this.traversalRing.replaceTraversal(
+                (Traversal.Admin<S, E>) oldTraversal,
+                (Traversal.Admin<S, E>) newTraversal);
+    }
+
     public List<String> getProjectKeys() {
         return this.projectKeys;
     }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyKeyStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyKeyStep.java
index ea1db27..9e7a0ab 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyKeyStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyKeyStep.java
@@ -29,7 +29,7 @@
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class PropertyKeyStep extends MapStep<Property, String> {
+public final class PropertyKeyStep extends ScalarMapStep<Property, String> {
 
     public PropertyKeyStep(final Traversal.Admin traversal) {
         super(traversal);
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyMapStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyMapStep.java
index 98a284b..ecc82f9 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyMapStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyMapStep.java
@@ -49,7 +49,7 @@
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  * @author Daniel Kuppitz (http://gremlin.guru)
  */
-public class PropertyMapStep<K,E> extends MapStep<Element, Map<K, E>>
+public class PropertyMapStep<K,E> extends ScalarMapStep<Element, Map<K, E>>
         implements TraversalParent, ByModulating, Configuring {
 
     protected final String[] propertyKeys;
@@ -61,15 +61,6 @@
     private Parameters parameters = new Parameters();
     private TraversalRing<K, E> traversalRing;
 
-    /**
-     * @deprecated As of release 3.4.0, replaced by {@link #PropertyMapStep(Traversal.Admin, PropertyType, String...)}.
-     */
-    @Deprecated
-    public PropertyMapStep(final Traversal.Admin traversal, final boolean includeTokens, final PropertyType propertyType, final String... propertyKeys) {
-        this(traversal, propertyType, propertyKeys);
-        this.configure(WithOptions.tokens, includeTokens ? WithOptions.all : WithOptions.none);
-    }
-
     public PropertyMapStep(final Traversal.Admin traversal, final PropertyType propertyType, final String... propertyKeys) {
         super(traversal);
         this.propertyKeys = propertyKeys;
@@ -78,6 +69,11 @@
         this.traversalRing = new TraversalRing<>();
     }
 
+    public PropertyMapStep(final Traversal.Admin traversal, final int options, final PropertyType propertyType, final String... propertyKeys) {
+        this(traversal, propertyType, propertyKeys);
+        this.configure(WithOptions.tokens, options);
+    }
+
     @Override
     protected Map<K, E> map(final Traverser.Admin<Element> traverser) {
         final Map<Object, Object> map = new LinkedHashMap<>();
@@ -167,14 +163,6 @@
         return propertyKeys;
     }
 
-    /**
-     * @deprecated As of release 3.4.0, replaced by {@link #getIncludedTokens()}.
-     */
-    @Deprecated
-    public boolean isIncludeTokens() {
-        return this.tokens != WithOptions.none;
-    }
-
     public String toString() {
         return StringFactory.stepString(this, Arrays.asList(this.propertyKeys),
                 this.traversalRing, this.returnType.name().toLowerCase());
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyValueStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyValueStep.java
index eab0ea6..6f41010 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyValueStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyValueStep.java
@@ -29,7 +29,7 @@
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class PropertyValueStep<E> extends MapStep<Property<E>, E> {
+public final class PropertyValueStep<E> extends ScalarMapStep<Property<E>, E> {
 
     public PropertyValueStep(final Traversal.Admin traversal) {
         super(traversal);
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/RangeLocalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/RangeLocalStep.java
index 905a80c..f72a0cb 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/RangeLocalStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/RangeLocalStep.java
@@ -36,7 +36,7 @@
 /**
  * @author Daniel Kuppitz (http://gremlin.guru)
  */
-public final class RangeLocalStep<S> extends MapStep<S, S> {
+public final class RangeLocalStep<S> extends ScalarMapStep<S, S> {
 
     private final long low;
     private final long high;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SackStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SackStep.java
index 3e0385b..7f12a00 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SackStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SackStep.java
@@ -28,7 +28,7 @@
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class SackStep<S, E> extends MapStep<S, E> {
+public final class SackStep<S, E> extends ScalarMapStep<S, E> {
 
     public SackStep(final Traversal.Admin traversal) {
         super(traversal);
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SampleLocalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SampleLocalStep.java
index 5f83c53..052ca15 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SampleLocalStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SampleLocalStep.java
@@ -21,6 +21,7 @@
 
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+import org.apache.tinkerpop.gremlin.process.traversal.step.Seedable;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
 
 import java.util.ArrayList;
@@ -36,9 +37,9 @@
  * @author Daniel Kuppitz (http://gremlin.guru)
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class SampleLocalStep<S> extends MapStep<S, S> {
+public final class SampleLocalStep<S> extends ScalarMapStep<S, S> implements Seedable {
 
-    private static final Random RANDOM = new Random();
+    private final Random random = new Random();
 
     private final int amountToSample;
 
@@ -48,6 +49,11 @@
     }
 
     @Override
+    public void resetSeed(final long seed) {
+        this.random.setSeed(seed);
+    }
+
+    @Override
     protected S map(final Traverser.Admin<S> traverser) {
         final S start = traverser.get();
         if (start instanceof Map) {
@@ -66,7 +72,7 @@
         final List<S> original = new ArrayList<>(collection);
         final List<S> target = new ArrayList<>();
         while (target.size() < this.amountToSample) {
-            target.add(original.remove(RANDOM.nextInt(original.size())));
+            target.add(original.remove(random.nextInt(original.size())));
         }
         return (S) target;
     }
@@ -78,7 +84,7 @@
         final List<Map.Entry> original = new ArrayList<>(map.entrySet());
         final Map target = new LinkedHashMap<>(this.amountToSample);
         while (target.size() < this.amountToSample) {
-            final Map.Entry entry = original.remove(RANDOM.nextInt(original.size()));
+            final Map.Entry entry = original.remove(random.nextInt(original.size()));
             target.put(entry.getKey(), entry.getValue());
         }
         return (S) target;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ScalarMapStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ScalarMapStep.java
new file mode 100644
index 0000000..78e0766
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ScalarMapStep.java
@@ -0,0 +1,44 @@
+/*
+ * 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;
+
+/**
+ * A type of {@link MapStep} class which will transform the object of one {@link Traverser} into another. This class
+ * simply requires the implementation of the {@link #map(Traverser.Admin)} method to extract the object of the given
+ * {@link Traverser} and return the transformation of that object as {@code E}.
+ *
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public abstract class ScalarMapStep<S, E> extends MapStep<S,E> {
+    public ScalarMapStep(final Traversal.Admin traversal) {
+        super(traversal);
+    }
+
+    @Override
+    protected Traverser.Admin<E> processNextStart() {
+        final Traverser.Admin<S> traverser = this.starts.next();
+        return traverser.split(this.map(traverser), this);
+    }
+
+    protected abstract E map(final Traverser.Admin<S> traverser);
+}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectOneStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectOneStep.java
index 2c7aa82..976c512 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectOneStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectOneStep.java
@@ -26,13 +26,14 @@
 import org.apache.tinkerpop.gremlin.process.traversal.step.Scoping;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
-import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
+import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.EmptyTraverser;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
+import java.util.NoSuchElementException;
 import java.util.Set;
 
 /**
@@ -52,9 +53,19 @@
     }
 
     @Override
-    protected E map(final Traverser.Admin<S> traverser) {
-        final E end = this.getNullableScopeValue(this.pop, this.selectKey, traverser);
-        return null != end ? TraversalUtil.applyNullable((S) end, this.selectTraversal) : null;
+    protected Traverser.Admin<E> processNextStart() throws NoSuchElementException {
+        final Traverser.Admin<S> traverser = this.starts.next();
+
+        try {
+            final S o = getScopeValue(pop, selectKey, traverser);
+            if (null == o) return traverser.split(null, this);
+            final Traverser.Admin<E> outTraverser = traverser.split(TraversalUtil.applyNullable(o, this.selectTraversal), this);
+            if (!(this.getTraversal().getParent() instanceof MatchStep))
+                PathProcessor.processTraverserPathLabels(outTraverser, this.keepLabels);
+            return outTraverser;
+        } catch (KeyNotFoundException nfe) {
+            return EmptyTraverser.instance();
+        }
     }
 
     @Override
@@ -103,6 +114,12 @@
     }
 
     @Override
+    public void replaceLocalChild(final Traversal.Admin<?, ?> oldTraversal, final Traversal.Admin<?, ?> newTraversal) {
+        if (null != this.selectTraversal && this.selectTraversal.equals(oldTraversal))
+            this.selectTraversal = this.integrateChild(newTraversal);
+    }
+
+    @Override
     public Set<TraverserRequirement> getRequirements() {
         return this.getSelfAndChildRequirements(TraverserRequirement.OBJECT, TraverserRequirement.SIDE_EFFECTS);
     }
@@ -126,14 +143,6 @@
         return this.keepLabels;
     }
 
-    @Override
-    protected Traverser.Admin<E> processNextStart() {
-        final Traverser.Admin<E> traverser = super.processNextStart();
-        if (!(this.getTraversal().getParent() instanceof MatchStep)) {
-            PathProcessor.processTraverserPathLabels(traverser, this.keepLabels);
-        }
-        return traverser;
-    }
 }
 
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectStep.java
index 875cf93..9edde9d 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectStep.java
@@ -26,7 +26,7 @@
 import org.apache.tinkerpop.gremlin.process.traversal.step.Scoping;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
-import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
+import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.EmptyTraverser;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalRing;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
@@ -38,10 +38,12 @@
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.NoSuchElementException;
 import java.util.Set;
 
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
+ * @author Stephen Mallette (http://stephen.genoprime.com)
  */
 public final class SelectStep<S, E> extends MapStep<S, Map<String, E>> implements Scoping, TraversalParent, PathProcessor, ByModulating {
 
@@ -61,19 +63,21 @@
     }
 
     @Override
-    protected Map<String, E> map(final Traverser.Admin<S> traverser) {
+    protected Traverser.Admin<Map<String, E>> processNextStart() throws NoSuchElementException {
+        final Traverser.Admin<S> traverser = this.starts.next();
         final Map<String, E> bindings = new LinkedHashMap<>(this.selectKeys.size(), 1.0f);
-        for (final String selectKey : this.selectKeys) {
-            final E end = this.getNullableScopeValue(this.pop, selectKey, traverser);
-            if (null != end)
+        try {
+            for (final String selectKey : this.selectKeys) {
+                final E end = this.getScopeValue(this.pop, selectKey, traverser);
                 bindings.put(selectKey, TraversalUtil.applyNullable(end, this.traversalRing.next()));
-            else {
-                this.traversalRing.reset();
-                return null;
             }
+        } catch (KeyNotFoundException nfe) {
+            return EmptyTraverser.instance();
+        } finally {
+            this.traversalRing.reset();
         }
-        this.traversalRing.reset();
-        return bindings;
+
+        return PathProcessor.processTraverserPathLabels(traverser.split(bindings, this), this.keepLabels);
     }
 
     @Override
@@ -119,6 +123,13 @@
     }
 
     @Override
+    public void replaceLocalChild(final Traversal.Admin<?, ?> oldTraversal, final Traversal.Admin<?, ?> newTraversal) {
+        this.traversalRing.replaceTraversal(
+                (Traversal.Admin<Object, E>) oldTraversal,
+                (Traversal.Admin<Object, E>) newTraversal);
+    }
+
+    @Override
     public Set<TraverserRequirement> getRequirements() {
         return this.getSelfAndChildRequirements(TraverserRequirement.OBJECT, TraverserRequirement.SIDE_EFFECTS);
     }
@@ -150,9 +161,4 @@
     public Set<String> getKeepLabels() {
         return this.keepLabels;
     }
-
-    @Override
-    protected Traverser.Admin<Map<String, E>> processNextStart() {
-        return PathProcessor.processTraverserPathLabels(super.processNextStart(), this.keepLabels);
-    }
 }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SumLocalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SumLocalStep.java
index 72e6539..3249e31 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SumLocalStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SumLocalStep.java
@@ -32,7 +32,7 @@
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  * @author Daniel Kuppitz (http://gremlin.guru)
  */
-public final class SumLocalStep<E extends Number, S extends Iterable<E>> extends MapStep<S, E> {
+public final class SumLocalStep<E extends Number, S extends Iterable<E>> extends ScalarMapStep<S, E> {
 
     public SumLocalStep(final Traversal.Admin traversal) {
         super(traversal);
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TailLocalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TailLocalStep.java
index ea678a5..336323e 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TailLocalStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TailLocalStep.java
@@ -34,7 +34,7 @@
 /**
  * @author Matt Frantz (http://github.com/mhfrantz)
  */
-public final class TailLocalStep<S> extends MapStep<S, S> {
+public final class TailLocalStep<S> extends ScalarMapStep<S, S> {
 
     private final long limit;
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalMapStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalMapStep.java
index 896b833..7dc82d7 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalMapStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalMapStep.java
@@ -22,16 +22,19 @@
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
+import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.EmptyTraverser;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 
 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)
+ * @author Stephen Mallette (http://stephen.genoprime.com)
  */
 public final class TraversalMapStep<S, E> extends MapStep<S, E> implements TraversalParent {
 
@@ -43,9 +46,10 @@
     }
 
     @Override
-    protected E map(final Traverser.Admin<S> traverser) {
+    protected Traverser.Admin<E> processNextStart() throws NoSuchElementException {
+        final Traverser.Admin<S> traverser = this.starts.next();
         final Iterator<E> iterator = TraversalUtil.applyAll(traverser, this.mapTraversal);
-        return iterator.hasNext() ? iterator.next() : null;
+        return  iterator.hasNext() ? traverser.split(iterator.next(), this) : EmptyTraverser.instance();
     }
 
     @Override
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalSelectStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalSelectStep.java
index 1d5ecd1..ff9f099 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalSelectStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalSelectStep.java
@@ -18,14 +18,15 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.step.map;
 
-import org.apache.tinkerpop.gremlin.process.traversal.Path;
 import org.apache.tinkerpop.gremlin.process.traversal.Pop;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import org.apache.tinkerpop.gremlin.process.traversal.step.ByModulating;
 import org.apache.tinkerpop.gremlin.process.traversal.step.PathProcessor;
+import org.apache.tinkerpop.gremlin.process.traversal.step.Scoping;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
+import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.EmptyTraverser;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 
@@ -34,14 +35,12 @@
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 
-
 /**
  * @author Daniel Kuppitz (http://gremlin.guru)
  */
-public final class TraversalSelectStep<S, E> extends MapStep<S, E> implements TraversalParent, PathProcessor, ByModulating {
+public final class TraversalSelectStep<S, E> extends MapStep<S, E> implements TraversalParent, PathProcessor, ByModulating, Scoping {
 
     private final Pop pop;
     private Traversal.Admin<S, E> keyTraversal;
@@ -55,26 +54,35 @@
     }
 
     @Override
-    protected E map(final Traverser.Admin<S> traverser) {
-        E end = null;
+    protected Traverser.Admin<E> processNextStart() {
+        final Traverser.Admin<S> traverser = this.starts.next();
         final Iterator<E> keyIterator = TraversalUtil.applyAll(traverser, this.keyTraversal);
         if (keyIterator.hasNext()) {
             final E key = keyIterator.next();
-            final Object object = traverser.get();
-            if (object instanceof Map && ((Map) object).containsKey(key))
-                end = (E) ((Map) object).get(key);
-            else if (key instanceof String) {
-                final String skey = (String) key;
-                if (traverser.getSideEffects().exists(skey)) {
-                    end = traverser.getSideEffects().get((String) key);
-                } else {
-                    final Path path = traverser.path();
-                    if (path.hasLabel(skey))
-                        end = null == pop ? path.get(skey) : path.get(pop, skey);
+            try {
+                final E end = getScopeValue(pop, key, traverser);
+                final Traverser.Admin<E> outTraverser = traverser.split(null == end ? null : TraversalUtil.applyNullable(end, this.selectTraversal), this);
+                if (!(this.getTraversal().getParent() instanceof MatchStep)) {
+                    PathProcessor.processTraverserPathLabels(outTraverser, this.keepLabels);
                 }
+                return outTraverser;
+            } catch (KeyNotFoundException nfe) {
+                return EmptyTraverser.instance();
             }
+        } else {
+            return EmptyTraverser.instance();
         }
-        return null != end ? TraversalUtil.applyNullable(end, this.selectTraversal) : null;
+    }
+
+    @Override
+    public Set<String> getScopeKeys() {
+        // can't return scope keys here because they aren't known prior to traversal execution and this method is
+        // used at strategy application time. not getting any test failures as a result of returning empty. assuming
+        // that strategies don't use Scoping in a way that requires the keys to be known and if they aren't doesn't
+        // hose the whole traversal. in the worst case, strategies will hopefully just leave steps alone rather than
+        // make their own assumptions that the step is not selecting anything. if that is happening somehow we might
+        // need to modify Scoping to better suite this runtime evaluation of the key.
+        return Collections.emptySet();
     }
 
     @Override
@@ -155,15 +163,6 @@
     public Set<String> getKeepLabels() {
         return this.keepLabels;
     }
-
-    @Override
-    protected Traverser.Admin<E> processNextStart() {
-        final Traverser.Admin<E> traverser = super.processNextStart();
-        if (!(this.getTraversal().getParent() instanceof MatchStep)) {
-            PathProcessor.processTraverserPathLabels(traverser, this.keepLabels);
-        }
-        return traverser;
-    }
 }
 
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TreeStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TreeStep.java
index 41310aa..1904859 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TreeStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TreeStep.java
@@ -64,6 +64,13 @@
     }
 
     @Override
+    public void replaceLocalChild(final Traversal.Admin<?, ?> oldTraversal, final Traversal.Admin<?, ?> newTraversal) {
+        this.traversalRing.replaceTraversal(
+                (Traversal.Admin<Object, Object>) oldTraversal,
+                (Traversal.Admin<Object, Object>) newTraversal);
+    }
+
+    @Override
     public Set<TraverserRequirement> getRequirements() {
         return this.getSelfAndChildRequirements(TraverserRequirement.PATH, TraverserRequirement.SIDE_EFFECTS);
     }
@@ -83,7 +90,6 @@
         return topTree;
     }
 
-
     @Override
     public TreeStep<S> clone() {
         final TreeStep<S> clone = (TreeStep<S>) super.clone();
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStep.java
index cee4346..7f1d42c 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStep.java
@@ -98,6 +98,14 @@
 
         final Element element = traverser.get();
 
+        // can't set cardinality if the element is something other than a vertex as only vertices can have
+        // a cardinality of properties. if we don't throw an error here we end up with a confusing cast exception
+        // which doesn't explain what went wrong
+        if (this.cardinality != null && !(element instanceof Vertex))
+            throw new IllegalStateException(String.format(
+                    "Property cardinality can only be set for a Vertex but the traversal encountered %s for key: %s",
+                    element.getClass().getSimpleName(), key));
+
         if (this.callbackRegistry != null && !callbackRegistry.getCallbacks().isEmpty()) {
             getTraversal().getStrategies().getStrategy(EventStrategy.class)
                     .ifPresent(eventStrategy -> {
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateGlobalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateGlobalStep.java
new file mode 100644
index 0000000..0f75963
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateGlobalStep.java
@@ -0,0 +1,168 @@
+/*
+ * 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.sideEffect;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Operator;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+import org.apache.tinkerpop.gremlin.process.traversal.step.ByModulating;
+import org.apache.tinkerpop.gremlin.process.traversal.step.LocalBarrier;
+import org.apache.tinkerpop.gremlin.process.traversal.step.SideEffectCapable;
+import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.AbstractStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.BulkSet;
+import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
+import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.TraverserSet;
+import org.apache.tinkerpop.gremlin.process.traversal.util.FastNoSuchElementException;
+import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil;
+import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
+import org.apache.tinkerpop.gremlin.util.function.BulkSetSupplier;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.function.Supplier;
+
+/**
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ */
+public final class AggregateGlobalStep<S> extends AbstractStep<S, S> implements SideEffectCapable<Collection, Collection>, TraversalParent, ByModulating, LocalBarrier<S> {
+
+    private Traversal.Admin<S, Object> aggregateTraversal = null;
+    private String sideEffectKey;
+    private TraverserSet<S> barrier;
+
+    public AggregateGlobalStep(final Traversal.Admin traversal, final String sideEffectKey) {
+        super(traversal);
+        this.sideEffectKey = sideEffectKey;
+        this.barrier = (TraverserSet<S>) this.traversal.getTraverserSetSupplier().get();
+        this.getTraversal().getSideEffects().registerIfAbsent(this.sideEffectKey, (Supplier) BulkSetSupplier.instance(), Operator.addAll);
+    }
+
+    @Override
+    public String getSideEffectKey() {
+        return this.sideEffectKey;
+    }
+
+    @Override
+    public String toString() {
+        return StringFactory.stepString(this, this.sideEffectKey, this.aggregateTraversal);
+    }
+
+    @Override
+    public void modulateBy(final Traversal.Admin<?, ?> aggregateTraversal) {
+        this.aggregateTraversal = this.integrateChild(aggregateTraversal);
+    }
+
+    @Override
+    public void replaceLocalChild(final Traversal.Admin<?, ?> oldTraversal, final Traversal.Admin<?, ?> newTraversal) {
+        if (null != this.aggregateTraversal && this.aggregateTraversal.equals(oldTraversal))
+            this.aggregateTraversal = this.integrateChild(newTraversal);
+    }
+
+    @Override
+    public List<Traversal.Admin<S, Object>> getLocalChildren() {
+        return null == this.aggregateTraversal ? Collections.emptyList() : Collections.singletonList(this.aggregateTraversal);
+    }
+
+    @Override
+    public Set<TraverserRequirement> getRequirements() {
+        return this.getSelfAndChildRequirements(TraverserRequirement.BULK, TraverserRequirement.SIDE_EFFECTS);
+    }
+
+    @Override
+    public AggregateGlobalStep<S> clone() {
+        final AggregateGlobalStep<S> clone = (AggregateGlobalStep<S>) super.clone();
+        clone.barrier = (TraverserSet<S>) this.traversal.getTraverserSetSupplier().get();
+        if (null != this.aggregateTraversal)
+            clone.aggregateTraversal = this.aggregateTraversal.clone();
+        return clone;
+    }
+
+    @Override
+    public void setTraversal(final Traversal.Admin<?, ?> parentTraversal) {
+        super.setTraversal(parentTraversal);
+        this.integrateChild(this.aggregateTraversal);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = super.hashCode() ^ this.sideEffectKey.hashCode();
+        if (this.aggregateTraversal != null)
+            result ^= this.aggregateTraversal.hashCode();
+        return result;
+    }
+
+    @Override
+    protected Traverser.Admin<S> processNextStart() {
+        if (this.barrier.isEmpty()) {
+            this.processAllStarts();
+        }
+        return this.barrier.remove();
+    }
+
+    @Override
+    public void processAllStarts() {
+        if (this.starts.hasNext()) {
+            final BulkSet<Object> bulkSet = new BulkSet<>();
+            while (this.starts.hasNext()) {
+                final Traverser.Admin<S> traverser = this.starts.next();
+                bulkSet.add(TraversalUtil.applyNullable(traverser, this.aggregateTraversal), traverser.bulk());
+                traverser.setStepId(this.getNextStep().getId()); // when barrier is reloaded, the traversers should be at the next step
+                this.barrier.add(traverser);
+            }
+            this.getTraversal().getSideEffects().add(this.sideEffectKey, bulkSet);
+        }
+    }
+
+    @Override
+    public boolean hasNextBarrier() {
+        if (this.barrier.isEmpty()) {
+            this.processAllStarts();
+        }
+        return !this.barrier.isEmpty();
+    }
+
+    @Override
+    public TraverserSet<S> nextBarrier() throws NoSuchElementException {
+        if (this.barrier.isEmpty()) {
+            this.processAllStarts();
+        }
+        if (this.barrier.isEmpty())
+            throw FastNoSuchElementException.instance();
+        else {
+            final TraverserSet<S> temp = this.barrier;
+            this.barrier = (TraverserSet<S>) this.traversal.getTraverserSetSupplier().get();
+            return temp;
+        }
+    }
+
+    @Override
+    public void addBarrier(final TraverserSet<S> barrier) {
+        this.barrier.addAll(barrier);
+    }
+
+    @Override
+    public void reset() {
+        super.reset();
+        this.barrier.clear();
+    }
+}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateLocalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateLocalStep.java
new file mode 100644
index 0000000..3c7c0fa
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateLocalStep.java
@@ -0,0 +1,112 @@
+/*
+ * 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.sideEffect;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Operator;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+import org.apache.tinkerpop.gremlin.process.traversal.step.ByModulating;
+import org.apache.tinkerpop.gremlin.process.traversal.step.SideEffectCapable;
+import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.BulkSet;
+import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
+import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil;
+import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
+import org.apache.tinkerpop.gremlin.util.function.BulkSetSupplier;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Supplier;
+
+/**
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ */
+public final class AggregateLocalStep<S> extends SideEffectStep<S> implements SideEffectCapable<Collection, Collection>, TraversalParent, ByModulating {
+
+    private Traversal.Admin<S, Object> storeTraversal = null;
+    private String sideEffectKey;
+
+    public AggregateLocalStep(final Traversal.Admin traversal, final String sideEffectKey) {
+        super(traversal);
+        this.sideEffectKey = sideEffectKey;
+        this.getTraversal().getSideEffects().registerIfAbsent(this.sideEffectKey, (Supplier) BulkSetSupplier.instance(), Operator.addAll);
+    }
+
+    @Override
+    protected void sideEffect(final Traverser.Admin<S> traverser) {
+        final BulkSet<Object> bulkSet = new BulkSet<>();
+        bulkSet.add(TraversalUtil.applyNullable(traverser, this.storeTraversal), traverser.bulk());
+        this.getTraversal().getSideEffects().add(this.sideEffectKey, bulkSet);
+    }
+
+    @Override
+    public String getSideEffectKey() {
+        return this.sideEffectKey;
+    }
+
+    @Override
+    public String toString() {
+        return StringFactory.stepString(this, this.sideEffectKey, this.storeTraversal);
+    }
+
+    @Override
+    public List<Traversal.Admin<S, Object>> getLocalChildren() {
+        return null == this.storeTraversal ? Collections.emptyList() : Collections.singletonList(this.storeTraversal);
+    }
+
+    @Override
+    public void modulateBy(final Traversal.Admin<?, ?> storeTraversal) {
+        this.storeTraversal = this.integrateChild(storeTraversal);
+    }
+
+    @Override
+    public void replaceLocalChild(final Traversal.Admin<?, ?> oldTraversal, final Traversal.Admin<?, ?> newTraversal) {
+        if (null != this.storeTraversal && this.storeTraversal.equals(oldTraversal))
+            this.storeTraversal = this.integrateChild(newTraversal);
+    }
+
+    @Override
+    public Set<TraverserRequirement> getRequirements() {
+        return this.getSelfAndChildRequirements(TraverserRequirement.SIDE_EFFECTS, TraverserRequirement.BULK);
+    }
+
+    @Override
+    public AggregateLocalStep<S> clone() {
+        final AggregateLocalStep<S> clone = (AggregateLocalStep<S>) super.clone();
+        if (null != this.storeTraversal)
+            clone.storeTraversal = this.storeTraversal.clone();
+        return clone;
+    }
+
+    @Override
+    public void setTraversal(final Traversal.Admin<?, ?> parentTraversal) {
+        super.setTraversal(parentTraversal);
+        this.integrateChild(this.storeTraversal);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = super.hashCode() ^ this.sideEffectKey.hashCode();
+        if (this.storeTraversal != null)
+            result ^= this.storeTraversal.hashCode();
+        return result;
+    }
+}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateStep.java
deleted file mode 100644
index 9c2ea48..0000000
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateStep.java
+++ /dev/null
@@ -1,162 +0,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.
- */
-package org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect;
-
-import org.apache.tinkerpop.gremlin.process.traversal.Operator;
-import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
-import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
-import org.apache.tinkerpop.gremlin.process.traversal.step.ByModulating;
-import org.apache.tinkerpop.gremlin.process.traversal.step.LocalBarrier;
-import org.apache.tinkerpop.gremlin.process.traversal.step.SideEffectCapable;
-import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.AbstractStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.BulkSet;
-import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
-import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.TraverserSet;
-import org.apache.tinkerpop.gremlin.process.traversal.util.FastNoSuchElementException;
-import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil;
-import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
-import org.apache.tinkerpop.gremlin.util.function.BulkSetSupplier;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.NoSuchElementException;
-import java.util.Set;
-import java.util.function.Supplier;
-
-/**
- * @author Marko A. Rodriguez (http://markorodriguez.com)
- */
-public final class AggregateStep<S> extends AbstractStep<S, S> implements SideEffectCapable<Collection, Collection>, TraversalParent, ByModulating, LocalBarrier<S> {
-
-    private Traversal.Admin<S, Object> aggregateTraversal = null;
-    private String sideEffectKey;
-    private TraverserSet<S> barrier;
-
-    public AggregateStep(final Traversal.Admin traversal, final String sideEffectKey) {
-        super(traversal);
-        this.sideEffectKey = sideEffectKey;
-        this.barrier = (TraverserSet<S>) this.traversal.getTraverserSetSupplier().get();
-        this.getTraversal().getSideEffects().registerIfAbsent(this.sideEffectKey, (Supplier) BulkSetSupplier.instance(), Operator.addAll);
-    }
-
-    @Override
-    public String getSideEffectKey() {
-        return this.sideEffectKey;
-    }
-
-    @Override
-    public String toString() {
-        return StringFactory.stepString(this, this.sideEffectKey, this.aggregateTraversal);
-    }
-
-    @Override
-    public void modulateBy(final Traversal.Admin<?, ?> aggregateTraversal) {
-        this.aggregateTraversal = this.integrateChild(aggregateTraversal);
-    }
-
-    @Override
-    public List<Traversal.Admin<S, Object>> getLocalChildren() {
-        return null == this.aggregateTraversal ? Collections.emptyList() : Collections.singletonList(this.aggregateTraversal);
-    }
-
-    @Override
-    public Set<TraverserRequirement> getRequirements() {
-        return this.getSelfAndChildRequirements(TraverserRequirement.BULK, TraverserRequirement.SIDE_EFFECTS);
-    }
-
-    @Override
-    public AggregateStep<S> clone() {
-        final AggregateStep<S> clone = (AggregateStep<S>) super.clone();
-        clone.barrier = (TraverserSet<S>) this.traversal.getTraverserSetSupplier().get();
-        if (null != this.aggregateTraversal)
-            clone.aggregateTraversal = this.aggregateTraversal.clone();
-        return clone;
-    }
-
-    @Override
-    public void setTraversal(final Traversal.Admin<?, ?> parentTraversal) {
-        super.setTraversal(parentTraversal);
-        this.integrateChild(this.aggregateTraversal);
-    }
-
-    @Override
-    public int hashCode() {
-        int result = super.hashCode() ^ this.sideEffectKey.hashCode();
-        if (this.aggregateTraversal != null)
-            result ^= this.aggregateTraversal.hashCode();
-        return result;
-    }
-
-    @Override
-    protected Traverser.Admin<S> processNextStart() {
-        if (this.barrier.isEmpty()) {
-            this.processAllStarts();
-        }
-        return this.barrier.remove();
-    }
-
-    @Override
-    public void processAllStarts() {
-        if (this.starts.hasNext()) {
-            final BulkSet<Object> bulkSet = new BulkSet<>();
-            while (this.starts.hasNext()) {
-                final Traverser.Admin<S> traverser = this.starts.next();
-                bulkSet.add(TraversalUtil.applyNullable(traverser, this.aggregateTraversal), traverser.bulk());
-                traverser.setStepId(this.getNextStep().getId()); // when barrier is reloaded, the traversers should be at the next step
-                this.barrier.add(traverser);
-            }
-            this.getTraversal().getSideEffects().add(this.sideEffectKey, bulkSet);
-        }
-    }
-
-    @Override
-    public boolean hasNextBarrier() {
-        if (this.barrier.isEmpty()) {
-            this.processAllStarts();
-        }
-        return !this.barrier.isEmpty();
-    }
-
-    @Override
-    public TraverserSet<S> nextBarrier() throws NoSuchElementException {
-        if (this.barrier.isEmpty()) {
-            this.processAllStarts();
-        }
-        if (this.barrier.isEmpty())
-            throw FastNoSuchElementException.instance();
-        else {
-            final TraverserSet<S> temp = this.barrier;
-            this.barrier = (TraverserSet<S>) this.traversal.getTraverserSetSupplier().get();
-            return temp;
-        }
-    }
-
-    @Override
-    public void addBarrier(final TraverserSet<S> barrier) {
-        this.barrier.addAll(barrier);
-    }
-
-    @Override
-    public void reset() {
-        super.reset();
-        this.barrier.clear();
-    }
-}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupCountSideEffectStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupCountSideEffectStep.java
index 88a1cb7..41ddeef 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupCountSideEffectStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupCountSideEffectStep.java
@@ -106,4 +106,10 @@
     public void modulateBy(final Traversal.Admin<?, ?> keyTraversal) throws UnsupportedOperationException {
         this.keyTraversal = this.integrateChild(keyTraversal);
     }
+
+    @Override
+    public void replaceLocalChild(final Traversal.Admin<?, ?> oldTraversal, final Traversal.Admin<?, ?> newTraversal) {
+        if (null != this.keyTraversal && this.keyTraversal.equals(oldTraversal))
+            this.keyTraversal = this.integrateChild(newTraversal);
+    }
 }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupSideEffectStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupSideEffectStep.java
index fd31bc3..9467467 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupSideEffectStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupSideEffectStep.java
@@ -24,13 +24,13 @@
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
 import org.apache.tinkerpop.gremlin.process.traversal.step.Barrier;
 import org.apache.tinkerpop.gremlin.process.traversal.step.ByModulating;
+import org.apache.tinkerpop.gremlin.process.traversal.step.Grouping;
 import org.apache.tinkerpop.gremlin.process.traversal.step.ProfilingAware;
 import org.apache.tinkerpop.gremlin.process.traversal.step.SideEffectCapable;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.GroupStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.ProfileStep;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
-import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 import org.apache.tinkerpop.gremlin.util.function.HashMapSupplier;
@@ -44,7 +44,8 @@
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class GroupSideEffectStep<S, K, V> extends SideEffectStep<S> implements SideEffectCapable<Map<K, ?>, Map<K, V>>, TraversalParent, ByModulating, ProfilingAware {
+public final class GroupSideEffectStep<S, K, V> extends SideEffectStep<S>
+        implements SideEffectCapable<Map<K, ?>, Map<K, V>>, TraversalParent, ByModulating, ProfilingAware, Grouping<S, K, V> {
 
     private char state = 'k';
     private Traversal.Admin<S, K> keyTraversal;
@@ -58,7 +59,7 @@
         super(traversal);
         this.sideEffectKey = sideEffectKey;
         this.valueTraversal = this.integrateChild(__.fold().asAdmin());
-        this.barrierStep = GroupStep.determineBarrierStep(this.valueTraversal);
+        this.barrierStep = determineBarrierStep(this.valueTraversal);
         this.getTraversal().getSideEffects().registerIfAbsent(this.sideEffectKey, HashMapSupplier.instance(),
                 new GroupStep.GroupBiOperator<>(null == this.barrierStep ?
                         Operator.assign :
@@ -75,17 +76,31 @@
     }
 
     @Override
+    public Traversal.Admin<S, K> getKeyTraversal() {
+        return this.keyTraversal;
+    }
+
+    @Override
+    public Traversal.Admin<S, V> getValueTraversal() {
+        return this.valueTraversal;
+    }
+
+    private void setValueTraversal(final Traversal.Admin valueTraversal) {
+        this.valueTraversal = this.integrateChild(convertValueTraversal(valueTraversal));
+        this.barrierStep = determineBarrierStep(this.valueTraversal);
+        this.getTraversal().getSideEffects().register(this.sideEffectKey, null,
+                new GroupStep.GroupBiOperator<>(null == this.barrierStep ?
+                        Operator.assign :
+                        this.barrierStep.getMemoryComputeKey().getReducer()));
+    }
+
+    @Override
     public void modulateBy(final Traversal.Admin<?, ?> kvTraversal) {
         if ('k' == this.state) {
             this.keyTraversal = this.integrateChild(kvTraversal);
             this.state = 'v';
         } else if ('v' == this.state) {
-            this.valueTraversal = this.integrateChild(GroupStep.convertValueTraversal(kvTraversal));
-            this.barrierStep = GroupStep.determineBarrierStep(this.valueTraversal);
-            this.getTraversal().getSideEffects().register(this.sideEffectKey, null,
-                    new GroupStep.GroupBiOperator<>(null == this.barrierStep ?
-                            Operator.assign :
-                            this.barrierStep.getMemoryComputeKey().getReducer()));
+            this.setValueTraversal(kvTraversal);
             this.state = 'x';
         } else {
             throw new IllegalStateException("The key and value traversals for group()-step have already been set: " + this);
@@ -93,6 +108,14 @@
     }
 
     @Override
+    public void replaceLocalChild(final Traversal.Admin<?, ?> oldTraversal, final Traversal.Admin<?, ?> newTraversal) {
+        if (null != this.keyTraversal && this.keyTraversal.equals(oldTraversal))
+            this.keyTraversal = this.integrateChild(newTraversal);
+        else if (null != this.valueTraversal && this.valueTraversal.equals(oldTraversal))
+            this.setValueTraversal(newTraversal);
+    }
+
+    @Override
     protected void sideEffect(final Traverser.Admin<S> traverser) {
         final Map<K, V> map = new HashMap<>(1);
         this.valueTraversal.reset();
@@ -101,7 +124,7 @@
         // reset the barrierStep as there are now ProfileStep instances present and the timers won't start right
         // without specific configuration through wrapping both the Barrier and ProfileStep in ProfiledBarrier
         if (resetBarrierForProfiling) {
-            barrierStep = GroupStep.determineBarrierStep(valueTraversal);
+            barrierStep = determineBarrierStep(valueTraversal);
 
             // the barrier only needs to be reset once
             resetBarrierForProfiling = false;
@@ -146,7 +169,7 @@
         if (null != this.keyTraversal)
             clone.keyTraversal = this.keyTraversal.clone();
         clone.valueTraversal = this.valueTraversal.clone();
-        clone.barrierStep = GroupStep.determineBarrierStep(clone.valueTraversal);
+        clone.barrierStep = determineBarrierStep(clone.valueTraversal);
         return clone;
     }
 
@@ -167,6 +190,6 @@
 
     @Override
     public Map<K, V> generateFinalResult(final Map<K, ?> object) {
-        return GroupStep.doFinalReduction((Map<K, Object>) object, this.valueTraversal);
+        return doFinalReduction((Map<K, Object>) object, this.valueTraversal);
     }
 }
\ No newline at end of file
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/IoStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/IoStep.java
index 64a9035..dc5f040 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/IoStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/IoStep.java
@@ -188,7 +188,7 @@
                 final GryoMapper.Builder builder = GryoMapper.build();
                 detectRegistries().forEach(builder::addRegistry);
                 return GryoWriter.build().mapper(builder.create()).create();
-            }else if (objectOrClass.equals(IO.graphml))
+            } else if (objectOrClass.equals(IO.graphml))
                 return GraphMLWriter.build().create();
             else {
                 try {
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SackValueStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SackValueStep.java
index 650140e..bd0e828 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SackValueStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SackValueStep.java
@@ -52,6 +52,12 @@
     }
 
     @Override
+    public void replaceLocalChild(final Traversal.Admin<?, ?> oldTraversal, final Traversal.Admin<?, ?> newTraversal) {
+        if (null != this.sackTraversal && this.sackTraversal.equals(oldTraversal))
+            this.sackTraversal = this.integrateChild(newTraversal);
+    }
+
+    @Override
     public List<Traversal.Admin<S, B>> getLocalChildren() {
         return null == this.sackTraversal ? Collections.emptyList() : Collections.singletonList(this.sackTraversal);
     }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/StoreStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/StoreStep.java
deleted file mode 100644
index ac5b0c6..0000000
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/StoreStep.java
+++ /dev/null
@@ -1,106 +0,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.
- */
-package org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect;
-
-import org.apache.tinkerpop.gremlin.process.traversal.Operator;
-import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
-import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
-import org.apache.tinkerpop.gremlin.process.traversal.step.ByModulating;
-import org.apache.tinkerpop.gremlin.process.traversal.step.SideEffectCapable;
-import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.BulkSet;
-import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
-import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil;
-import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
-import org.apache.tinkerpop.gremlin.util.function.BulkSetSupplier;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.function.Supplier;
-
-/**
- * @author Marko A. Rodriguez (http://markorodriguez.com)
- */
-public final class StoreStep<S> extends SideEffectStep<S> implements SideEffectCapable<Collection, Collection>, TraversalParent, ByModulating {
-
-    private Traversal.Admin<S, Object> storeTraversal = null;
-    private String sideEffectKey;
-
-    public StoreStep(final Traversal.Admin traversal, final String sideEffectKey) {
-        super(traversal);
-        this.sideEffectKey = sideEffectKey;
-        this.getTraversal().getSideEffects().registerIfAbsent(this.sideEffectKey, (Supplier) BulkSetSupplier.instance(), Operator.addAll);
-    }
-
-    @Override
-    protected void sideEffect(final Traverser.Admin<S> traverser) {
-        final BulkSet<Object> bulkSet = new BulkSet<>();
-        bulkSet.add(TraversalUtil.applyNullable(traverser, this.storeTraversal), traverser.bulk());
-        this.getTraversal().getSideEffects().add(this.sideEffectKey, bulkSet);
-    }
-
-    @Override
-    public String getSideEffectKey() {
-        return this.sideEffectKey;
-    }
-
-    @Override
-    public String toString() {
-        return StringFactory.stepString(this, this.sideEffectKey, this.storeTraversal);
-    }
-
-    @Override
-    public List<Traversal.Admin<S, Object>> getLocalChildren() {
-        return null == this.storeTraversal ? Collections.emptyList() : Collections.singletonList(this.storeTraversal);
-    }
-
-    @Override
-    public void modulateBy(final Traversal.Admin<?, ?> storeTraversal) {
-        this.storeTraversal = this.integrateChild(storeTraversal);
-    }
-
-    @Override
-    public Set<TraverserRequirement> getRequirements() {
-        return this.getSelfAndChildRequirements(TraverserRequirement.SIDE_EFFECTS, TraverserRequirement.BULK);
-    }
-
-    @Override
-    public StoreStep<S> clone() {
-        final StoreStep<S> clone = (StoreStep<S>) super.clone();
-        if (null != this.storeTraversal)
-            clone.storeTraversal = this.storeTraversal.clone();
-        return clone;
-    }
-
-    @Override
-    public void setTraversal(final Traversal.Admin<?, ?> parentTraversal) {
-        super.setTraversal(parentTraversal);
-        this.integrateChild(this.storeTraversal);
-    }
-
-    @Override
-    public int hashCode() {
-        int result = super.hashCode() ^ this.sideEffectKey.hashCode();
-        if (this.storeTraversal != null)
-            result ^= this.storeTraversal.hashCode();
-        return result;
-    }
-}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/TreeSideEffectStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/TreeSideEffectStep.java
index 2d43ddc..c3f0fbd 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/TreeSideEffectStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/TreeSideEffectStep.java
@@ -119,6 +119,13 @@
     }
 
     @Override
+    public void replaceLocalChild(final Traversal.Admin<?, ?> oldTraversal, final Traversal.Admin<?, ?> newTraversal) {
+        this.traversalRing.replaceTraversal(
+                (Traversal.Admin<Object, Object>) oldTraversal,
+                (Traversal.Admin<Object, Object>) newTraversal);
+    }
+
+    @Override
     public Set<TraverserRequirement> getRequirements() {
         return this.getSelfAndChildRequirements(TraverserRequirement.PATH, TraverserRequirement.SIDE_EFFECTS);
     }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/AbstractStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/AbstractStep.java
index b4844f9..89dbc06 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/AbstractStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/AbstractStep.java
@@ -21,6 +21,7 @@
 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.traverser.util.EmptyTraverser;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.TraverserSet;
 import org.apache.tinkerpop.gremlin.process.traversal.util.EmptyTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalInterruptedException;
@@ -42,7 +43,7 @@
     protected String id = Traverser.Admin.HALT;
     protected Traversal.Admin traversal;
     protected ExpandableStepIterator<S> starts;
-    protected Traverser.Admin<E> nextEnd = null;
+    protected Traverser.Admin<E> nextEnd = EmptyTraverser.instance();
     protected boolean traverserStepIdAndLabelsSetByChild = false;
 
     protected Step<?, S> previousStep = EmptyStep.instance();
@@ -82,7 +83,7 @@
     @Override
     public void reset() {
         this.starts.clear();
-        this.nextEnd = null;
+        this.nextEnd = EmptyTraverser.instance();
     }
 
     @Override
@@ -96,6 +97,11 @@
     }
 
     @Override
+    public boolean hasStarts() {
+        return this.starts.hasNext();
+    }
+
+    @Override
     public void setPreviousStep(final Step<?, S> step) {
         this.previousStep = step;
     }
@@ -117,17 +123,17 @@
 
     @Override
     public Traverser.Admin<E> next() {
-        if (null != this.nextEnd) {
+        if (EmptyTraverser.instance() != this.nextEnd) {
             try {
                 return this.prepareTraversalForNextStep(this.nextEnd);
             } finally {
-                this.nextEnd = null;
+                this.nextEnd = EmptyTraverser.instance();
             }
         } else {
             while (true) {
                 if (Thread.interrupted()) throw new TraversalInterruptedException();
                 final Traverser.Admin<E> traverser = this.processNextStart();
-                if (null != traverser.get() && 0 != traverser.bulk())
+                if (traverser.bulk() > 0)
                     return this.prepareTraversalForNextStep(traverser);
             }
         }
@@ -135,17 +141,17 @@
 
     @Override
     public boolean hasNext() {
-        if (null != this.nextEnd)
+        if (EmptyTraverser.instance() != this.nextEnd)
             return true;
         else {
             try {
                 while (true) {
                     if (Thread.interrupted()) throw new TraversalInterruptedException();
                     this.nextEnd = this.processNextStart();
-                    if (null != this.nextEnd.get() && 0 != this.nextEnd.bulk())
+                    if (this.nextEnd.bulk() > 0)
                         return true;
                     else
-                        this.nextEnd = null;
+                        this.nextEnd = EmptyTraverser.instance();
                 }
             } catch (final NoSuchElementException e) {
                 return false;
@@ -178,7 +184,7 @@
             clone.starts = new ExpandableStepIterator<>(clone, (TraverserSet<S>) traversal.getTraverserSetSupplier().get());
             clone.previousStep = EmptyStep.instance();
             clone.nextStep = EmptyStep.instance();
-            clone.nextEnd = null;
+            clone.nextEnd = EmptyTraverser.instance();
             clone.traversal = EmptyTraversal.instance();
             clone.labels = new LinkedHashSet<>(this.labels);
             clone.reset();
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/EmptyStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/EmptyStep.java
index b377c81..704cce3 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/EmptyStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/EmptyStep.java
@@ -50,6 +50,11 @@
     }
 
     @Override
+    public boolean hasStarts() {
+        return false;
+    }
+
+    @Override
     public void addStart(final Traverser.Admin<S> start) {
 
     }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/ImmutablePath.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/ImmutablePath.java
index 623b810..1b5e562 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/ImmutablePath.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/ImmutablePath.java
@@ -28,6 +28,7 @@
 import java.util.HashSet;
 import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -35,7 +36,8 @@
  */
 public class ImmutablePath implements Path, Serializable, Cloneable {
 
-    private static final ImmutablePath TAIL_PATH = new ImmutablePath(null, null, null);
+    private static final Object END = EmptyPath.instance();
+    private static final ImmutablePath TAIL_PATH = new ImmutablePath(null, END, null);
 
     private ImmutablePath previousPath;
     private Object currentObject;
@@ -58,7 +60,7 @@
     }
 
     private final boolean isTail() {
-        return null == this.currentObject;
+        return END.equals(this.currentObject);
     }
 
     @Override
@@ -230,7 +232,7 @@
         while (true) {
             if (currentPath.isTail())
                 break;
-            hashCodes[index] = currentPath.currentObject.hashCode();
+            hashCodes[index] = Objects.hashCode(currentPath.currentObject);
             currentPath = currentPath.previousPath;
             index--;
         }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/Parameters.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/Parameters.java
index 5c86ad9..f16fd70 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/Parameters.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/Parameters.java
@@ -37,6 +37,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.function.Supplier;
 
@@ -73,6 +74,17 @@
     }
 
     /**
+     * Checks for existence of a key and value in a parameter set.
+     *
+     * @param key the key to check
+     * @param value the value to check
+     * @return {@code true} if the key and value are present and {@code false} otherwise
+     */
+    public boolean contains(final Object key, final Object value) {
+        return this.contains(key) && this.parameters.get(key).contains(value);
+    }
+
+    /**
      * Renames a key in the parameter set.
      *
      * @param oldKey the key to rename
@@ -180,27 +192,24 @@
             if (!(keyValues[ix] instanceof String) && !(keyValues[ix] instanceof T) && !(keyValues[ix] instanceof Traversal))
                 throw new IllegalArgumentException("The provided key/value array must have a String, T, or Traversal on even array indices");
 
-            if (keyValues[ix + 1] != null) {
-
-                // check both key and value for traversal instances. track the list of traversals that are present so
-                // that elsewhere in Parameters there is no need to iterate all values to not find any. also grab
-                // available labels in traversal values
-                for (int iy = 0; iy < 2; iy++) {
-                    if (keyValues[ix + iy] instanceof Traversal.Admin) {
-                        final Traversal.Admin t = (Traversal.Admin) keyValues[ix + iy];
-                        addTraversal(t);
-                        if (parent != null) parent.integrateChild(t);
-                    }
+            // check both key and value for traversal instances. track the list of traversals that are present so
+            // that elsewhere in Parameters there is no need to iterate all values to not find any. also grab
+            // available labels in traversal values
+            for (int iy = 0; iy < 2; iy++) {
+                if (keyValues[ix + iy] instanceof Traversal.Admin) {
+                    final Traversal.Admin t = (Traversal.Admin) keyValues[ix + iy];
+                    addTraversal(t);
+                    if (parent != null) parent.integrateChild(t);
                 }
+            }
 
-                List<Object> values = this.parameters.get(keyValues[ix]);
-                if (null == values) {
-                    values = new ArrayList<>();
-                    values.add(keyValues[ix + 1]);
-                    this.parameters.put(keyValues[ix], values);
-                } else {
-                    values.add(keyValues[ix + 1]);
-                }
+            List<Object> values = this.parameters.get(keyValues[ix]);
+            if (null == values) {
+                values = new ArrayList<>();
+                values.add(keyValues[ix + 1]);
+                this.parameters.put(keyValues[ix], values);
+            } else {
+                values.add(keyValues[ix + 1]);
             }
         }
     }
@@ -254,7 +263,7 @@
         for (final Map.Entry<Object, List<Object>> entry : this.parameters.entrySet()) {
             result ^= entry.getKey().hashCode();
             for (final Object value : entry.getValue()) {
-                result ^= Integer.rotateLeft(value.hashCode(), entry.getKey().hashCode());
+                result ^= Integer.rotateLeft(Objects.hashCode(value), entry.getKey().hashCode());
             }
         }
         return result;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/TraversalStrategyProxy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/TraversalStrategyProxy.java
index de57ddd..ea4415a 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/TraversalStrategyProxy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/TraversalStrategyProxy.java
@@ -19,7 +19,7 @@
 
 package org.apache.tinkerpop.gremlin.process.traversal.strategy;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/ElementIdStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/ElementIdStrategy.java
index 25a2833..903ea3a 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/ElementIdStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/ElementIdStrategy.java
@@ -18,8 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration;
 
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.MapConfiguration;
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.configuration2.MapConfiguration;
 import org.apache.tinkerpop.gremlin.process.traversal.P;
 import org.apache.tinkerpop.gremlin.process.traversal.step.Parameterizing;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/HaltedTraverserStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/HaltedTraverserStrategy.java
index 3f02c40..988d818 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/HaltedTraverserStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/HaltedTraverserStrategy.java
@@ -19,8 +19,8 @@
 
 package org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration;
 
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.MapConfiguration;
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.configuration2.MapConfiguration;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/OptionsStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/OptionsStrategy.java
index fd64d7f..1a7a81f 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/OptionsStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/OptionsStrategy.java
@@ -18,8 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration;
 
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.MapConfiguration;
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.configuration2.MapConfiguration;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/PartitionStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/PartitionStrategy.java
index 111609b..2103bf5 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/PartitionStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/PartitionStrategy.java
@@ -18,8 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration;
 
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.MapConfiguration;
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.configuration2.MapConfiguration;
 import org.apache.tinkerpop.gremlin.process.traversal.P;
 import org.apache.tinkerpop.gremlin.process.traversal.step.Parameterizing;
 import org.apache.tinkerpop.gremlin.process.traversal.Step;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/RequirementsStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/RequirementsStrategy.java
index 78c48b8..cd9d663 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/RequirementsStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/RequirementsStrategy.java
@@ -44,12 +44,12 @@
 
     @Override
     public void apply(final Traversal.Admin<?, ?> traversal) {
-        if (traversal.getParent() instanceof EmptyStep && !this.requirements.isEmpty())
+        if (traversal.isRoot() && !this.requirements.isEmpty())
             traversal.addStep(new RequirementsStep<>(traversal, this.requirements));
     }
 
     public static void addRequirements(final TraversalStrategies traversalStrategies, final TraverserRequirement... requirements) {
-        RequirementsStrategy strategy = (RequirementsStrategy) traversalStrategies.toList().stream().filter(s -> s instanceof RequirementsStrategy).findAny().orElse(null);
+        RequirementsStrategy strategy = (RequirementsStrategy) traversalStrategies.getStrategy(RequirementsStrategy.class).orElse(null);
         if (null == strategy) {
             strategy = new RequirementsStrategy();
             traversalStrategies.addStrategies(strategy);
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SackStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SackStrategy.java
index 7124b61..0341cac 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SackStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SackStrategy.java
@@ -51,7 +51,7 @@
 
     @Override
     public void apply(final Traversal.Admin<?, ?> traversal) {
-        if (traversal.getParent() instanceof EmptyStep)
+        if (traversal.isRoot())
             traversal.getSideEffects().setSack(this.initialValue, this.splitOperator, this.mergeOperator);
     }
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SeedStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SeedStrategy.java
new file mode 100644
index 0000000..dbf9324
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SeedStrategy.java
@@ -0,0 +1,79 @@
+/*
+ * 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.strategy.decoration;
+
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.configuration2.MapConfiguration;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.step.Seedable;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A strategy that resets the specified {@code seed} value for {@link Seedable} steps, which in turn will produce
+ * deterministic results from those steps. It is important to note that when using this strategy that it only
+ * guarantees deterministic results from a step but not from an entire traversal. For example, if a graph does no
+ * guarantee iteration order for {@code g.V()} then repeated runs of {@code g.V().coin(0.5)} with this strategy
+ * will return the same number of results but not necessarily the same ones. The same problem can occur in OLAP-based
+ * traversals where iteration order is not explicitly guaranteed. The only way to ensure completely deterministic
+ * results in that sense is to apply some form of {@code order()} in these cases
+ */
+public class SeedStrategy extends AbstractTraversalStrategy<TraversalStrategy.DecorationStrategy>
+        implements TraversalStrategy.DecorationStrategy {
+
+    private final long seed;
+
+    public SeedStrategy(final long seed) {
+        this.seed = seed;
+    }
+
+    public long getSeed() {
+        return seed;
+    }
+
+    @Override
+    public void apply(final Traversal.Admin<?, ?> traversal) {
+        final List<Seedable> seedableSteps = TraversalHelper.getStepsOfAssignableClass(Seedable.class, traversal);
+        for (final Seedable seedableStepsToReset : seedableSteps) {
+            seedableStepsToReset.resetSeed(seed);
+        }
+    }
+
+    public static final String ID_SEED = "seed";
+
+    public static SeedStrategy create(final Configuration configuration) {
+        if (!configuration.containsKey(ID_SEED))
+            throw new IllegalArgumentException("SeedStrategy configuration requires a 'seed' value");
+
+        return new SeedStrategy(Long.parseLong(configuration.getProperty(ID_SEED).toString()));
+    }
+
+    @Override
+    public Configuration getConfiguration() {
+        final Map<String, Object> map = new HashMap<>();
+        map.put(STRATEGY, SeedStrategy.class.getCanonicalName());
+        map.put(ID_SEED, this.seed);
+        return new MapConfiguration(map);
+    }
+}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SideEffectStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SideEffectStrategy.java
index 6ec0068..430f5ab 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SideEffectStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SideEffectStrategy.java
@@ -44,13 +44,13 @@
 
     @Override
     public void apply(final Traversal.Admin<?, ?> traversal) {
-        if (traversal.getParent() instanceof EmptyStep) {
+        if (traversal.isRoot()) {
             this.sideEffects.forEach(triplet -> traversal.getSideEffects().register(triplet.getValue0(), triplet.getValue1(), triplet.getValue2()));
         }
     }
 
     public static <A> void addSideEffect(final TraversalStrategies traversalStrategies, final String key, final A value, final BinaryOperator<A> reducer) {
-        SideEffectStrategy strategy = (SideEffectStrategy) traversalStrategies.toList().stream().filter(s -> s instanceof SideEffectStrategy).findAny().orElse(null);
+        SideEffectStrategy strategy = traversalStrategies.getStrategy(SideEffectStrategy.class).orElse(null);
         if (null == strategy) {
             strategy = new SideEffectStrategy();
             traversalStrategies.addStrategies(strategy);
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategy.java
index a57a7d3..5333d2b 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategy.java
@@ -18,13 +18,13 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration;
 
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.MapConfiguration;
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.configuration2.MapConfiguration;
 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.dsl.graph.__;
-import org.apache.tinkerpop.gremlin.process.traversal.lambda.ElementValueTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.lambda.ValueTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
 import org.apache.tinkerpop.gremlin.process.traversal.step.filter.ClassFilterStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.filter.FilterStep;
@@ -150,18 +150,7 @@
             traversal.getStartStep().removeLabel(MARKER);
             return;
         }
-        for (final Step step : traversal.getSteps()) {
-            if (step instanceof TraversalParent) {
-                for (final Traversal.Admin t : ((TraversalParent) step).getLocalChildren()) {
-                    this.apply(t);
-                    t.getStartStep().addLabel(MARKER);
-                }
-                for (final Traversal.Admin t : ((TraversalParent) step).getGlobalChildren()) {
-                    this.apply(t);
-                    t.getStartStep().addLabel(MARKER);
-                }
-            }
-        }
+
         //
         final List<GraphStep> graphSteps = TraversalHelper.getStepsOfAssignableClass(GraphStep.class, traversal);
         final List<VertexStep> vertexSteps = TraversalHelper.getStepsOfAssignableClass(VertexStep.class, traversal);
@@ -231,19 +220,19 @@
                         }
                     } else {
                         Stream.concat(((TraversalParent) step).getGlobalChildren().stream(), ((TraversalParent) step).getLocalChildren().stream())
-                                .filter(t -> t instanceof ElementValueTraversal)
+                                .filter(t -> t instanceof ValueTraversal)
                                 .forEach(t -> {
                                     final char propertyType = processesPropertyType(step.getPreviousStep());
                                     if ('p' != propertyType) {
                                         final Traversal.Admin<?, ?> temp = new DefaultTraversal<>();
-                                        temp.addStep(new PropertiesStep<>(temp, PropertyType.PROPERTY, ((ElementValueTraversal) t).getPropertyKey()));
+                                        temp.addStep(new PropertiesStep<>(temp, PropertyType.PROPERTY, ((ValueTraversal) t).getPropertyKey()));
                                         if ('v' == propertyType)
                                             TraversalHelper.insertTraversal(0, nonCheckPropertyCriterion.clone(), temp);
                                         else
                                             temp.addStep(checkPropertyCriterion.clone());
                                         temp.addStep(new PropertyValueStep<>(temp));
                                         temp.setParent((TraversalParent) step);
-                                        ((ElementValueTraversal) t).setBypassTraversal(temp);
+                                        ((ValueTraversal) t).setBypassTraversal(temp);
                                     }
                                 });
                     }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/finalization/MatchAlgorithmStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/finalization/MatchAlgorithmStrategy.java
index a70e22a..a0577ef 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/finalization/MatchAlgorithmStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/finalization/MatchAlgorithmStrategy.java
@@ -18,8 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization;
 
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.MapConfiguration;
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.configuration2.MapConfiguration;
 import org.apache.tinkerpop.gremlin.process.traversal.Step;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/finalization/ProfileStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/finalization/ProfileStrategy.java
index ceedb38..dedd567 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/finalization/ProfileStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/finalization/ProfileStrategy.java
@@ -45,9 +45,11 @@
 
     @Override
     public void apply(final Traversal.Admin<?, ?> traversal) {
-        if ((traversal.getParent() instanceof EmptyStep || traversal.getParent() instanceof VertexProgramStep) &&
+        if (!traversal.getEndStep().getLabels().contains(MARKER) &&
+                (traversal.isRoot() || traversal.getParent() instanceof VertexProgramStep) &&
                 TraversalHelper.hasStepOfAssignableClassRecursively(ProfileSideEffectStep.class, traversal))
             TraversalHelper.applyTraversalRecursively(t -> t.getEndStep().addLabel(MARKER), traversal);
+
         if (traversal.getEndStep().getLabels().contains(MARKER)) {
             traversal.getEndStep().removeLabel(MARKER);
             // Add .profile() step after every pre-existing step.
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/finalization/ReferenceElementStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/finalization/ReferenceElementStrategy.java
index 41e1325..ebb0423 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/finalization/ReferenceElementStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/finalization/ReferenceElementStrategy.java
@@ -21,7 +21,7 @@
 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.step.map.MapStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.ScalarMapStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.ProfileSideEffectStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.EmptyStep;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
@@ -56,7 +56,7 @@
         return INSTANCE;
     }
 
-    public static class ReferenceElementStep<S, E> extends MapStep<S, E> {
+    public static class ReferenceElementStep<S, E> extends ScalarMapStep<S, E> {
 
         public ReferenceElementStep(final Traversal.Admin traversal) {
             super(traversal);
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/ByModulatorOptimizationStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/ByModulatorOptimizationStrategy.java
new file mode 100644
index 0000000..0faaef9
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/ByModulatorOptimizationStrategy.java
@@ -0,0 +1,139 @@
+/*
+ * 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.strategy.optimization;
+
+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.lambda.IdentityTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.lambda.TokenTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.lambda.ValueTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.step.ByModulating;
+import org.apache.tinkerpop.gremlin.process.traversal.step.Grouping;
+import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.FoldStep;
+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.PropertiesStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.PropertyKeyStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.PropertyValueStep;
+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.strategy.AbstractTraversalStrategy;
+import org.apache.tinkerpop.gremlin.structure.PropertyType;
+import org.apache.tinkerpop.gremlin.structure.T;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * This strategy looks for standard traversals in by-modulators and replaces them with more optimized traversals
+ * (e.g. {@code TokenTraversal}) if possible.
+ * <p/>
+ *
+ * @author Daniel Kuppitz (http://gremlin.guru)
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ * @example <pre>
+ * __.path().by(id())                        // is replaced by __.path().by(id)
+ * __.dedup().by(label())                    // is replaced by __.dedup().by(label)
+ * __.order().by(values("name"))             // is replaced by __.order().by("name")
+ * __.group().by().by(values("name").fold()) // is replaced by __.group().by("name")
+ * </pre>
+ */
+public final class ByModulatorOptimizationStrategy extends AbstractTraversalStrategy<TraversalStrategy.OptimizationStrategy>
+        implements TraversalStrategy.OptimizationStrategy {
+
+    private static final ByModulatorOptimizationStrategy INSTANCE = new ByModulatorOptimizationStrategy();
+
+    // when PathProcessorStrategy is present for withComputer() you need to ensure it always executes first because
+    // it does some manipulation to select().by(t) in some cases to turn it to select().map(t) in which case this
+    // strategy has nothing to do. if it were to occur first then that optimization wouldn't work as expected.
+    private static final Set<Class<? extends OptimizationStrategy>> PRIORS = new HashSet<>(Arrays.asList(
+            PathProcessorStrategy.class, IdentityRemovalStrategy.class));
+
+    private ByModulatorOptimizationStrategy() {
+    }
+
+    public static ByModulatorOptimizationStrategy instance() {
+        return INSTANCE;
+    }
+
+    private void optimizeByModulatingTraversal(final TraversalParent step, final Traversal.Admin<?, ?> traversal) {
+        if (traversal == null) return;
+        final List<Step> steps = traversal.asAdmin().getSteps();
+        if (steps.size() == 1) {
+            final Step singleStep = steps.get(0);
+            optimizeForStep(step, traversal, singleStep);
+        }
+    }
+
+    private void optimizeForStep(final TraversalParent step, final Traversal.Admin<?, ?> traversal, final Step singleStep) {
+        if (singleStep instanceof PropertiesStep) {
+            final PropertiesStep ps = (PropertiesStep) singleStep;
+            if (ps.getReturnType().equals(PropertyType.VALUE) && ps.getPropertyKeys().length == 1) {
+                step.replaceLocalChild(traversal, new ValueTraversal<>(ps.getPropertyKeys()[0]));
+            }
+        } else if (singleStep instanceof IdStep) {
+            step.replaceLocalChild(traversal, new TokenTraversal<>(T.id));
+        } else if (singleStep instanceof LabelStep) {
+            step.replaceLocalChild(traversal, new TokenTraversal<>(T.label));
+        } else if (singleStep instanceof PropertyKeyStep) {
+            step.replaceLocalChild(traversal, new TokenTraversal<>(T.key));
+        } else if (singleStep instanceof PropertyValueStep) {
+            step.replaceLocalChild(traversal, new TokenTraversal<>(T.value));
+        } else if (singleStep instanceof IdentityStep) {
+            step.replaceLocalChild(traversal, new IdentityTraversal<>());
+        }
+    }
+
+    @Override
+    public void apply(final Traversal.Admin<?, ?> traversal) {
+        final Step step = traversal.getParent().asStep();
+        if (step instanceof ByModulating && step instanceof TraversalParent) {
+            final TraversalParent byModulatingStep = (TraversalParent) step;
+            if (step instanceof Grouping) {
+                final Grouping grouping = (Grouping) step;
+                optimizeByModulatingTraversal(byModulatingStep, grouping.getKeyTraversal());
+
+                // the value by() needs different handling because by(Traversal) only equals by(String) or by(T)
+                // if the traversal does a fold().
+                final Traversal.Admin<?, ?> currentValueTraversal = grouping.getValueTraversal();
+                final List<Step> stepsInCurrentValueTraversal = currentValueTraversal.getSteps();
+                if (stepsInCurrentValueTraversal.size() == 1 && stepsInCurrentValueTraversal.get(0) instanceof IdentityStep)
+                    optimizeForStep(byModulatingStep, currentValueTraversal, stepsInCurrentValueTraversal.get(0));
+                else if (stepsInCurrentValueTraversal.size() == 2 && stepsInCurrentValueTraversal.get(1) instanceof FoldStep)
+                    optimizeForStep(byModulatingStep, currentValueTraversal, stepsInCurrentValueTraversal.get(0));
+
+            } else {
+                for (final Traversal.Admin<?, ?> byModulatingTraversal : byModulatingStep.getLocalChildren()) {
+                    optimizeByModulatingTraversal(byModulatingStep, byModulatingTraversal);
+                }
+            }
+        }
+    }
+
+    @Override
+    public Set<Class<? extends OptimizationStrategy>> applyPrior() {
+        return PRIORS;
+    }
+}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/IdentityRemovalStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/IdentityRemovalStrategy.java
index 3c4a875..ca6657d 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/IdentityRemovalStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/IdentityRemovalStrategy.java
@@ -21,10 +21,13 @@
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.IdentityStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.ComputerAwareStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.EmptyStep;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
 
+import java.util.List;
+
 /**
  * {@code IdentityRemovalStrategy} looks for {@link IdentityStep} instances and removes them.
  * If the identity step is labeled, its labels are added to the previous step.
@@ -46,13 +49,27 @@
 
     @Override
     public void apply(final Traversal.Admin<?, ?> traversal) {
+        // if there is just one step we would keep the step whether it was identity() or not.
         if (traversal.getSteps().size() <= 1)
             return;
 
         for (final IdentityStep<?> identityStep : TraversalHelper.getStepsOfClass(IdentityStep.class, traversal)) {
+            // with no labels on the identity() it can just be dropped. if there are labels then they should be
+            // moved to the previous step. if there is no previous step then this is a start of a labelled traversal
+            // and is kept
             if (identityStep.getLabels().isEmpty() || !(identityStep.getPreviousStep() instanceof EmptyStep)) {
-                TraversalHelper.copyLabels(identityStep, identityStep.getPreviousStep(), false);
-                traversal.removeStep(identityStep);
+
+                // for branch()/union() type steps an EndStep gets added which would lead to something like:
+                // [UnionStep([[VertexStep(OUT,vertex), EndStep], [EndStep], [VertexStep(OUT,vertex), EndStep]])]
+                // if the identity() was removed. seems to make sense to account for that case so that the traversal
+                // gets to be:
+                // [UnionStep([[VertexStep(OUT,vertex), EndStep], [IdentityStep, EndStep], [VertexStep(OUT,vertex), EndStep]])]
+                // EndStep seems to just behave like a identity() in the above case, but perhaps it is more consistent
+                // to keep the identity() placeholder rather than a step that doesn't actually exist
+                if (!(identityStep.getNextStep() instanceof ComputerAwareStep.EndStep && traversal.getSteps().size() == 2)) {
+                    TraversalHelper.copyLabels(identityStep, identityStep.getPreviousStep(), false);
+                    traversal.removeStep(identityStep);
+                }
             }
         }
     }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/IncidentToAdjacentStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/IncidentToAdjacentStrategy.java
index e70e54a..75d55ad 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/IncidentToAdjacentStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/IncidentToAdjacentStrategy.java
@@ -125,7 +125,7 @@
     @Override
     public void apply(final Traversal.Admin<?, ?> traversal) {
         // using a hidden label marker to denote whether the traversal should not be processed by this strategy
-        if ((traversal.getParent() instanceof EmptyStep || traversal.getParent() instanceof VertexProgramStep) &&
+        if ((traversal.isRoot() || traversal.getParent() instanceof VertexProgramStep) &&
                 TraversalHelper.hasStepOfAssignableClassRecursively(INVALIDATING_STEP_CLASSES, traversal))
             TraversalHelper.applyTraversalRecursively(t -> t.getStartStep().addLabel(MARKER), traversal);
         if (traversal.getStartStep().getLabels().contains(MARKER)) {
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java
index f5f980f..bec170d 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java
@@ -96,7 +96,7 @@
                         step instanceof OrStep && InlineFilterStrategy.processOrStep((OrStep) step, traversal) ||
                         step instanceof AndStep && InlineFilterStrategy.processAndStep((AndStep) step, traversal);
             }
-            if (!changed && traversal.getParent() instanceof EmptyStep) {
+            if (!changed && traversal.isRoot()) {
                 final Iterator<MatchStep> matchStepIterator = TraversalHelper.getStepsOfClass(MatchStep.class, traversal).iterator();
                 while (!changed && matchStepIterator.hasNext()) {
                     if (InlineFilterStrategy.processMatchStep(matchStepIterator.next(), traversal))
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/PathRetractionStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/PathRetractionStrategy.java
index e6ba8f3..cd29b28 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/PathRetractionStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/PathRetractionStrategy.java
@@ -33,6 +33,7 @@
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.MatchStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.NoOpBarrierStep;
 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.util.EmptyStep;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
@@ -76,14 +77,7 @@
 
     @Override
     public void apply(final Traversal.Admin<?, ?> traversal) {
-        // do not apply this strategy if there are lambdas as you can't introspect to know what path information the lambdas are using
-        // do not apply this strategy if a PATH requirement step is being used (in the future, we can do PATH requirement lookhead to be more intelligent about its usage)
-        // do not apply this strategy if a VertexProgramStep is present with LABELED_PATH requirements
-        if (traversal.getParent() instanceof EmptyStep &&
-                TraversalHelper.anyStepRecursively(step -> step instanceof LambdaHolder ||
-                        step.getRequirements().contains(TraverserRequirement.PATH) ||
-                        (step instanceof VertexProgramStep &&
-                                step.getRequirements().contains(TraverserRequirement.LABELED_PATH)), traversal)) {
+        if (traversal.isRoot() && isNotApplicable(traversal)) {
             TraversalHelper.applyTraversalRecursively(t -> t.getEndStep().addLabel(MARKER), traversal);
         }
 
@@ -115,10 +109,16 @@
             // add the keep labels to the path processor
             if (currentStep instanceof PathProcessor) {
                 final PathProcessor pathProcessor = (PathProcessor) currentStep;
-                if (currentStep instanceof MatchStep &&
-                        (currentStep.getNextStep().equals(EmptyStep.instance()) ||
-                                currentStep.getNextStep() instanceof DedupGlobalStep ||
-                                currentStep.getNextStep() instanceof SelectOneStep && currentStep.getNextStep().getNextStep() instanceof FilterStep)) {
+                // in versions prior to 3.5.0 we use to only keep labels if match() was last
+                // or was followed by dedup() or select().where(), but the pattern matching
+                // wasn't too smart and thus produced inconsistent/unexpected outputs. trying
+                // to make gremlin be a bit less surprising for users and ultimately this seemed
+                // like too much magic. finally, we really shouldn't rely have strategies relying
+                // to heavily on one another for results to be consistent. a traversal should
+                // produce the same results irrespective of zero, one or more strategies being
+                // applied. so, for now this change adds back a bit of overhead in managing some
+                // labels but produces results users expect.
+                if (currentStep instanceof MatchStep) {
                     pathProcessor.setKeepLabels(((MatchStep) currentStep).getMatchStartLabels());
                     pathProcessor.getKeepLabels().addAll(((MatchStep) currentStep).getMatchEndLabels());
                 } else {
@@ -222,7 +222,7 @@
             keeperTrail.addAll(levelLabels);
         }
 
-        for (final Step currentStep : traversal.getSteps()) {
+        for (final Step<?,?> currentStep : traversal.getSteps()) {
             // go back through current level and add all keepers
             // if there is one more RepeatSteps in this traversal's lineage, preserve keep labels
             if (currentStep instanceof PathProcessor) {
@@ -233,6 +233,21 @@
         }
     }
 
+    /**
+     * Determines if the strategy should be applied or not. It returns {@code true} and is "not applicable" when the
+     * following conditions are met:
+     * <ul>
+     *     <li>If there are lambdas as you can't introspect to know what path information the lambdas are using</li>
+     *     <li>If a PATH requirement step is being used (in the future, we can do PATH requirement lookhead to be more intelligent about its usage)</li>
+     *     <li>If a VertexProgramStep is present with LABELED_PATH requirements</li>
+     * </ul>
+     */
+    private static boolean isNotApplicable(final Traversal.Admin<?, ?> traversal) {
+        return TraversalHelper.anyStepRecursively(step -> step instanceof LambdaHolder ||
+                step.getRequirements().contains(TraverserRequirement.PATH) ||
+                (step instanceof VertexProgramStep && step.getRequirements().contains(TraverserRequirement.LABELED_PATH)), traversal);
+    }
+
     private void applyToChildren(final Set<String> keepLabels, final List<Traversal.Admin<Object, Object>> children) {
         for (final Traversal.Admin<Object, Object> child : children) {
             TraversalHelper.applyTraversalRecursively(trav -> addLabels(trav, keepLabels), child);
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RepeatUnrollStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RepeatUnrollStrategy.java
index 2b08f17..be82d0c 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RepeatUnrollStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RepeatUnrollStrategy.java
@@ -67,7 +67,8 @@
         if (TraversalHelper.onGraphComputer(traversal))
             return;
 
-        final boolean lazyBarrierStrategyInstalled = traversal.getStrategies().getStrategy(LazyBarrierStrategy.class).isPresent();
+        final boolean lazyBarrierStrategyInstalled = TraversalHelper.getRootTraversal(traversal).
+                getStrategies().getStrategy(LazyBarrierStrategy.class).isPresent();
 
         for (int i = 0; i < traversal.getSteps().size(); i++) {
             if (traversal.getSteps().get(i) instanceof RepeatStep) {
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/AbstractWarningVerificationStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/AbstractWarningVerificationStrategy.java
index 52c9410..8bdf0ee 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/AbstractWarningVerificationStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/AbstractWarningVerificationStrategy.java
@@ -18,12 +18,10 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.strategy.verification;
 
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.MapConfiguration;
-import org.apache.tinkerpop.gremlin.process.traversal.Step;
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.configuration2.MapConfiguration;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.VertexStep;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/EdgeLabelVerificationStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/EdgeLabelVerificationStrategy.java
index ff1e835..2d49ecb 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/EdgeLabelVerificationStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/EdgeLabelVerificationStrategy.java
@@ -18,8 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.strategy.verification;
 
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.MapConfiguration;
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.configuration2.MapConfiguration;
 import org.apache.tinkerpop.gremlin.process.traversal.Step;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/LambdaRestrictionStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/LambdaRestrictionStrategy.java
index 642d17a..71999c5 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/LambdaRestrictionStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/LambdaRestrictionStrategy.java
@@ -34,11 +34,11 @@
  *
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  * @example <pre>
- * __.out().map(v -> v.get().value("name"))           // throws an IllegalStateException
- * __.out().filter(v -> v.bulk() > 2)                 // throws an IllegalStateException
- * __.choose(v -> v.sack() == 1,out(),in())           // throws an IllegalStateException
- * __.select().by(v -> v.get().id())                  // throws an IllegalStateException
- * __.order().by(a,b -> a > b)                        // throws an IllegalStateException
+ * __.out().map(v -&gt; v.get().value("name"))           // throws an IllegalStateException
+ * __.out().filter(v -&gt; v.bulk() &gt; 2)              // throws an IllegalStateException
+ * __.choose(v -&gt; v.sack() == 1,out(),in())           // throws an IllegalStateException
+ * __.select().by(v -&gt; v.get().id())                  // throws an IllegalStateException
+ * __.order().by(a,b -&gt; a &gt; b)                        // throws an IllegalStateException
  * </pre>
  */
 public final class LambdaRestrictionStrategy extends AbstractTraversalStrategy<TraversalStrategy.VerificationStrategy> implements TraversalStrategy.VerificationStrategy {
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ReservedKeysVerificationStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ReservedKeysVerificationStrategy.java
index b106884..9d0d25f 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ReservedKeysVerificationStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ReservedKeysVerificationStrategy.java
@@ -18,8 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.strategy.verification;
 
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.MapConfiguration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.process.traversal.Step;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.step.Parameterizing;
@@ -32,9 +31,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/StandardVerificationStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/StandardVerificationStrategy.java
index fc33c69..5a41c92 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/StandardVerificationStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/StandardVerificationStrategy.java
@@ -51,8 +51,8 @@
 
     @Override
     public void apply(final Traversal.Admin<?, ?> traversal) {
-        if (!traversal.getStrategies().toList().contains(ComputerFinalizationStrategy.instance()) &&
-                !traversal.getStrategies().toList().contains(ComputerVerificationStrategy.instance())) {
+        if (!traversal.getStrategies().getStrategy(ComputerFinalizationStrategy.class).isPresent() &&
+                !traversal.getStrategies().getStrategy(ComputerVerificationStrategy.class).isPresent()) {
             if (!TraversalHelper.getStepsOfAssignableClass(VertexComputing.class, traversal).isEmpty())
                 throw new VerificationException("VertexComputing steps must be executed with a GraphComputer: " + TraversalHelper.getStepsOfAssignableClass(VertexComputing.class, traversal), traversal);
         }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslator.java
new file mode 100644
index 0000000..181ee1f
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslator.java
@@ -0,0 +1,448 @@
+/*
+ *  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.translator;
+
+import org.apache.commons.configuration2.ConfigurationConverter;
+import org.apache.commons.text.StringEscapeUtils;
+import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
+import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
+import org.apache.tinkerpop.gremlin.process.traversal.Script;
+import org.apache.tinkerpop.gremlin.process.traversal.TextP;
+import org.apache.tinkerpop.gremlin.process.traversal.Translator;
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.TraversalStrategyProxy;
+import org.apache.tinkerpop.gremlin.process.traversal.util.ConnectiveP;
+import org.apache.tinkerpop.gremlin.process.traversal.util.OrP;
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+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.util.StringFactory;
+import org.apache.tinkerpop.gremlin.util.function.Lambda;
+
+import java.sql.Timestamp;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.UUID;
+
+/**
+ * Converts bytecode to a C# string of Gremlin.
+ *
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public final class DotNetTranslator implements Translator.ScriptTranslator {
+
+    private final String traversalSource;
+    private final TypeTranslator typeTranslator;
+
+    private static final List<String> methodsWithArgsNotNeedingGeneric = Arrays.asList(GraphTraversal.Symbols.group,
+            GraphTraversal.Symbols.groupCount, GraphTraversal.Symbols.sack);
+
+    private DotNetTranslator(final String traversalSource, final TypeTranslator typeTranslator) {
+        this.traversalSource = traversalSource;
+        this.typeTranslator = typeTranslator;
+    }
+
+    /**
+     * Creates the translator with a {@code false} argument to {@code withParameters} using
+     * {@link #of(String, boolean)}.
+     */
+    public static DotNetTranslator of(final String traversalSource) {
+        return of(traversalSource, false);
+    }
+
+    /**
+     * Creates the translator with the {@link DefaultTypeTranslator} passing the {@code withParameters} option to it
+     * which will handle type translation in a fashion that should typically increase cache hits and reduce
+     * compilation times if enabled at the sacrifice to rewriting of the script that could reduce readability.
+     */
+    public static DotNetTranslator of(final String traversalSource, final boolean withParameters) {
+        return of(traversalSource, new DefaultTypeTranslator(withParameters));
+    }
+
+    /**
+     * Creates the translator with a custom {@link TypeTranslator} instance.
+     */
+    public static DotNetTranslator of(final String traversalSource, final TypeTranslator typeTranslator) {
+        return new DotNetTranslator(traversalSource, typeTranslator);
+    }
+
+    @Override
+    public Script translate(final Bytecode bytecode) {
+        return typeTranslator.apply(traversalSource, bytecode);
+    }
+
+    @Override
+    public String getTargetLanguage() {
+        return "gremlin-dotnet";
+    }
+
+    @Override
+    public String toString() {
+        return StringFactory.translatorString(this);
+    }
+
+    @Override
+    public String getTraversalSource() {
+        return this.traversalSource;
+    }
+
+    /**
+     * Performs standard type translation for the TinkerPop types to C#.
+     */
+    public static class DefaultTypeTranslator extends AbstractTypeTranslator {
+
+        public DefaultTypeTranslator(final boolean withParameters) {
+            super(withParameters);
+        }
+
+        @Override
+        protected String getNullSyntax() {
+            return "null";
+        }
+
+        @Override
+        protected String getSyntax(final String o) {
+            return "\"" + StringEscapeUtils.escapeJava(o) + "\"";
+        }
+
+        @Override
+        protected String getSyntax(final Boolean o) {
+            return o.toString();
+        }
+
+        @Override
+        protected String getSyntax(final Date o) {
+            return "DateTimeOffset.FromUnixTimeMilliseconds(" + o.getTime() + ")";
+        }
+
+        @Override
+        protected String getSyntax(final Timestamp o) {
+            return "DateTimeOffset.FromUnixTimeMilliseconds(" + o.getTime() + ")";
+        }
+
+        @Override
+        protected String getSyntax(final UUID o) {
+            return "new Guid(\"" + o.toString() + "\")";
+        }
+
+        @Override
+        protected String getSyntax(final Lambda o) {
+            return "Lambda.Groovy(\"" + StringEscapeUtils.escapeEcmaScript(o.getLambdaScript().trim()) + "\")";
+        }
+
+        @Override
+        protected String getSyntax(final SackFunctions.Barrier o) {
+            return "Barrier." + SymbolHelper.toCSharp(o.toString());
+        }
+
+        @Override
+        protected String getSyntax(final VertexProperty.Cardinality o) {
+            return "Cardinality." + SymbolHelper.toCSharp(o.toString());
+        }
+
+        @Override
+        protected String getSyntax(final TraversalOptionParent.Pick o) {
+            return "Pick." + SymbolHelper.toCSharp(o.toString());
+        }
+
+        @Override
+        protected String getSyntax(final Number o) {
+            return o.toString();
+        }
+
+        @Override
+        protected Script produceScript(final Set<?> o) {
+            final Iterator<?> iterator = o.iterator();
+            script.append("new HashSet<object> {");
+
+            while (iterator.hasNext()) {
+                final Object nextItem = iterator.next();
+                convertToScript(nextItem);
+                if (iterator.hasNext())
+                    script.append(", ");
+            }
+
+            return script.append("}");
+        }
+
+        @Override
+        protected Script produceScript(final List<?> o) {
+            final Iterator<?> iterator = ((List<?>) o).iterator();
+            script.append("new List<object> {");
+
+            while (iterator.hasNext()) {
+                final Object nextItem = iterator.next();
+                convertToScript(nextItem);
+                if (iterator.hasNext())
+                    script.append(", ");
+            }
+
+            return script.append("}");
+        }
+
+        @Override
+        protected Script produceScript(final Map<?, ?> o) {
+            script.append("new Dictionary<object,object> {");
+            produceKeyValuesForMap(o);
+            return script.append("}");
+        }
+
+        @Override
+        protected Script produceScript(final Class<?> o) {
+            return script.append(o.getCanonicalName());
+        }
+
+        @Override
+        protected Script produceScript(final Enum<?> o) {
+            final String e = o instanceof Direction ?
+                    o.name().substring(0,1).toUpperCase() + o.name().substring(1).toLowerCase() :
+                    o.name().substring(0,1).toUpperCase() + o.name().substring(1);
+            return script.append(o.getDeclaringClass().getSimpleName() + "." + e);
+        }
+
+        @Override
+        protected Script produceScript(final Vertex o) {
+            script.append("new Vertex(");
+            convertToScript(o.id());
+            script.append(", ");
+            convertToScript(o.label());
+            return script.append(")");
+        }
+
+        @Override
+        protected Script produceScript(final Edge o) {
+            script.append("new Edge(");
+            convertToScript(o.id());
+            script.append(", new Vertex(");
+            convertToScript(o.outVertex().id());
+            script.append(", ");
+            convertToScript(o.outVertex().label());
+            script.append("), ");
+            convertToScript(o.label());
+            script.append(", new Vertex(");
+            convertToScript(o.inVertex().id());
+            script.append(", ");
+            convertToScript(o.inVertex().label());
+            return script.append("))");
+        }
+
+        @Override
+        protected Script produceScript(final VertexProperty<?> o) {
+            script.append("new VertexProperty(");
+            convertToScript(o.id());
+            script.append(", ");
+            convertToScript(o.label());
+            script.append(", ");
+            convertToScript(o.value());
+            script.append(", ");
+            return script.append("null)");
+        }
+
+        @Override
+        protected Script produceScript(final TraversalStrategyProxy<?> o) {
+            if (o.getConfiguration().isEmpty()) {
+                return script.append("new " + o.getStrategyClass().getSimpleName() + "()");
+            } else {
+                script.append("new " + o.getStrategyClass().getSimpleName() + "(");
+                final Iterator<String> keys = o.getConfiguration().getKeys();
+                while (keys.hasNext()) {
+                    final String k = keys.next();
+                    script.append(k);
+                    script.append(": ");
+                    convertToScript(o.getConfiguration().getProperty(k));
+                    if (keys.hasNext())
+                        script.append(", ");
+                }
+
+                return script.append(")");
+            }
+        }
+
+        private Script produceKeyValuesForMap(final Map<?,?> m) {
+            final Iterator<? extends Map.Entry<?, ?>> itty = m.entrySet().iterator();
+            while (itty.hasNext()) {
+                final Map.Entry<?,?> entry = itty.next();
+                script.append("{");
+                convertToScript(entry.getKey());
+                script.append(", ");
+                convertToScript(entry.getValue());
+                script.append("}");
+                if (itty.hasNext())
+                    script.append(", ");
+            }
+            return script;
+        }
+
+        @Override
+        protected Script produceScript(final String traversalSource, final Bytecode o) {
+            script.append(traversalSource);
+            for (final Bytecode.Instruction instruction : o.getInstructions()) {
+                final String methodName = instruction.getOperator();
+                // perhaps too many if/then conditions for specifying generics. doesnt' seem like there is a clear
+                // way to refactor this more nicely though.
+                if (0 == instruction.getArguments().length) {
+                    if (methodName.equals(GraphTraversal.Symbols.fold) && o.getSourceInstructions().size() + o.getStepInstructions().size() > 1)
+                        script.append(".").append(resolveSymbol(methodName).replace("<object>", "")).append("()");
+                    else
+                        script.append(".").append(resolveSymbol(methodName)).append("()");
+                } else {
+                    if (methodsWithArgsNotNeedingGeneric.contains(methodName) ||
+                            (methodName.equals(GraphTraversal.Symbols.inject) && Arrays.stream(instruction.getArguments()).noneMatch(Objects::isNull)))
+                        script.append(".").append(resolveSymbol(methodName).replace("<object>", "").replace("<object,object>", "")).append("(");
+                    else
+                        script.append(".").append(resolveSymbol(methodName)).append("(");
+
+                    // have to special case withSack() because UnaryOperator and BinaryOperator signatures
+                    // make it impossible for the interpreter to figure out which function to call. specifically we need
+                    // to discern between:
+                    //     withSack(A initialValue, UnaryOperator<A> splitOperator)
+                    //     withSack(A initialValue, BinaryOperator<A> splitOperator)
+                    // and:
+                    //     withSack(Supplier<A> initialValue, UnaryOperator<A> mergeOperator)
+                    //     withSack(Supplier<A> initialValue, BinaryOperator<A> mergeOperator)
+                    if (methodName.equals(TraversalSource.Symbols.withSack) &&
+                            instruction.getArguments().length == 2 && instruction.getArguments()[1] instanceof Lambda) {
+                        final String castFirstArgTo = instruction.getArguments()[0] instanceof Lambda ? "ISupplier" : "";
+                        final Lambda secondArg = (Lambda) instruction.getArguments()[1];
+                        final String castSecondArgTo = secondArg.getLambdaArguments() == 1 ? "IUnaryOperator" : "IBinaryOperator";
+                        if (!castFirstArgTo.isEmpty())
+                            script.append(String.format("(%s) ", castFirstArgTo));
+                        convertToScript(instruction.getArguments()[0]);
+                        script.append(", (").append(castSecondArgTo).append(") ");
+                        convertToScript(instruction.getArguments()[1]);
+                        script.append(",");
+                    } else {
+                        for (final Object object : instruction.getArguments()) {
+                            // overloads might have trouble with null. add more as we find them i guess
+                            if (null == object && methodName.equals(GraphTraversal.Symbols.addV))
+                                script.append("(string) ");
+                            convertToScript(object);
+                            script.append(",");
+                        }
+                    }
+                    script.setCharAtEnd(')');
+                }
+            }
+            return script;
+        }
+
+        @Override
+        protected Script produceScript(final P<?> p) {
+            if (p instanceof TextP) {
+                script.append("TextP.").append(SymbolHelper.toCSharp(p.getBiPredicate().toString())).append("(");
+                convertToScript(p.getValue());
+            } else if (p instanceof ConnectiveP) {
+                // ConnectiveP gets some special handling because it's reduced to and(P, P, P) and we want it
+                // generated the way it was written which was P.and(P).and(P)
+                final List<P<?>> list = ((ConnectiveP) p).getPredicates();
+                final String connector = p instanceof OrP ? "Or" : "And";
+                for (int i = 0; i < list.size(); i++) {
+                    produceScript(list.get(i));
+
+                    // for the first/last P there is no parent to close
+                    if (i > 0 && i < list.size() - 1) script.append(")");
+
+                    // add teh connector for all but last P
+                    if (i < list.size() - 1) {
+                        script.append(".").append(connector).append("(");
+                    }
+                }
+            } else {
+                script.append("P.").append(SymbolHelper.toCSharp(p.getBiPredicate().toString())).append("(");
+                convertToScript(p.getValue());
+            }
+            script.append(")");
+            return script;
+        }
+
+        protected String resolveSymbol(final String methodName) {
+            return SymbolHelper.toCSharp(methodName);
+        }
+    }
+
+    static final class SymbolHelper {
+
+        private final static Map<String, String> TO_CS_MAP = new HashMap<>();
+        private final static Map<String, String> FROM_CS_MAP = new HashMap<>();
+
+        static {
+            TO_CS_MAP.put(GraphTraversal.Symbols.branch, "Branch<object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.cap, "Cap<object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.choose, "Choose<object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.coalesce, "Coalesce<object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.constant, "Constant<object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.elementMap, "ElementMap<object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.flatMap, "FlatMap<object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.fold, "Fold<object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.group, "Group<object,object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.groupCount, "GroupCount<object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.index, "Index<object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.inject, "Inject<object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.io, "Io<object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.limit, "Limit<object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.local, "Local<object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.match, "Match<object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.map, "Map<object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.max, "Max<object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.min, "Min<object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.mean, "Mean<object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.optional, "Optional<object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.project, "Project<object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.properties, "Properties<object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.range, "Range<object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.sack, "Sack<object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.select, "Select<object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.skip, "Skip<object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.sum, "Sum<object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.tail, "Tail<object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.unfold, "Unfold<object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.union, "Union<object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.value, "Value<object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.valueMap, "ValueMap<object,object>");
+            TO_CS_MAP.put(GraphTraversal.Symbols.values, "Values<object>");
+            //
+            TO_CS_MAP.forEach((k, v) -> FROM_CS_MAP.put(v, k));
+        }
+
+        private SymbolHelper() {
+            // static methods only, do not instantiate
+        }
+
+        public static String toCSharp(final String symbol) {
+            return TO_CS_MAP.getOrDefault(symbol, symbol.substring(0,1).toUpperCase() + symbol.substring(1));
+        }
+
+        public static String toJava(final String symbol) {
+            return FROM_CS_MAP.getOrDefault(symbol, symbol.substring(0,1).toLowerCase() + symbol.substring(1));
+        }
+
+    }
+}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslator.java
index 7335fc7..f11378b 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslator.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslator.java
@@ -1,33 +1,33 @@
 /*
- * 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
+ *  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
+ *  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.translator;
 
-import org.apache.commons.configuration.ConfigurationConverter;
-import org.apache.commons.lang.StringEscapeUtils;
+import org.apache.commons.configuration2.ConfigurationConverter;
+import org.apache.commons.text.StringEscapeUtils;
 import org.apache.tinkerpop.gremlin.jsr223.CoreImports;
 import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
 import org.apache.tinkerpop.gremlin.process.traversal.P;
 import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
+import org.apache.tinkerpop.gremlin.process.traversal.Script;
 import org.apache.tinkerpop.gremlin.process.traversal.TextP;
 import org.apache.tinkerpop.gremlin.process.traversal.Translator;
-import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
-import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.TraversalStrategyProxy;
 import org.apache.tinkerpop.gremlin.process.traversal.util.ConnectiveP;
@@ -38,13 +38,15 @@
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 import org.apache.tinkerpop.gremlin.util.function.Lambda;
 
+import java.math.BigDecimal;
+import java.math.BigInteger;
 import java.sql.Timestamp;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Date;
-import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Optional;
 import java.util.Set;
 import java.util.UUID;
 import java.util.stream.Collectors;
@@ -54,6 +56,7 @@
  *
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  * @author Stephen Mallette (http://stephen.genoprime.com)
+ * @author Stark Arya (sandszhou.zj@alibaba-inc.com)
  */
 public final class GroovyTranslator implements Translator.ScriptTranslator {
 
@@ -65,20 +68,33 @@
         this.typeTranslator = typeTranslator;
     }
 
+    /**
+     * Creates the translator with a {@code false} argument to {@code withParameters} using
+     * {@link #of(String, boolean)}.
+     */
     public static GroovyTranslator of(final String traversalSource) {
-        return of(traversalSource, null);
+        return of(traversalSource, false);
     }
 
+    /**
+     * Creates the translator with the {@link DefaultTypeTranslator} passing the {@code withParameters} option to it
+     * which will handle type translation in a fashion that should typically increase cache hits and reduce
+     * compilation times if enabled at the sacrifice to rewriting of the script that could reduce readability.
+     */
+    public static GroovyTranslator of(final String traversalSource, final boolean withParameters) {
+        return of(traversalSource, new DefaultTypeTranslator(withParameters));
+    }
+
+    /**
+     * Creates the translator with a custom {@link TypeTranslator} instance.
+     */
     public static GroovyTranslator of(final String traversalSource, final TypeTranslator typeTranslator) {
-        return new GroovyTranslator(traversalSource,
-                Optional.ofNullable(typeTranslator).orElseGet(DefaultTypeTranslator::new));
+        return new GroovyTranslator(traversalSource, typeTranslator);
     }
 
-    ///////
-
     @Override
-    public String translate(final Bytecode bytecode) {
-        return typeTranslator.apply(traversalSource, bytecode).toString();
+    public Script translate(final Bytecode bytecode) {
+        return typeTranslator.apply(traversalSource, bytecode);
     }
 
     @Override
@@ -99,153 +115,121 @@
     /**
      * Performs standard type translation for the TinkerPop types to Groovy.
      */
-    public static class DefaultTypeTranslator implements TypeTranslator {
+    public static class DefaultTypeTranslator extends AbstractTypeTranslator {
+
+        public DefaultTypeTranslator(final boolean withParameters) {
+            super(withParameters);
+        }
 
         @Override
-        public Object apply(final String traversalSource, final Object o) {
-            if (o instanceof Bytecode)
-                return internalTranslate(traversalSource, (Bytecode) o);
+        protected String getNullSyntax() {
+            return "null";
+        }
+
+        @Override
+        protected String getSyntax(final String o) {
+            return (o.contains("\"") ? "\"\"\"" + StringEscapeUtils.escapeJava(o) + "\"\"\"" : "\"" + StringEscapeUtils.escapeJava(o) + "\"")
+                    .replace("$", "\\$");
+        }
+
+        @Override
+        protected String getSyntax(final Boolean o) {
+            return o.toString();
+        }
+
+        @Override
+        protected String getSyntax(final Date o) {
+            return "new Date(" + o.getTime() + ")";
+        }
+
+        @Override
+        protected String getSyntax(final Timestamp o) {
+            return "new Timestamp(" + o.getTime() + ")";
+        }
+
+        @Override
+        protected String getSyntax(final UUID o) {
+            return "UUID.fromString('" + o.toString() + "')";
+        }
+
+        @Override
+        protected String getSyntax(final Lambda o) {
+            final String lambdaString = o.getLambdaScript().trim();
+            return lambdaString.startsWith("{") ? lambdaString : "{" + lambdaString + "}";
+        }
+
+        @Override
+        protected String getSyntax(final SackFunctions.Barrier o) {
+            return "SackFunctions.Barrier." + o.toString();
+        }
+
+        @Override
+        protected String getSyntax(final VertexProperty.Cardinality o) {
+            return "VertexProperty.Cardinality." + o.toString();
+        }
+
+        @Override
+        protected String getSyntax(final TraversalOptionParent.Pick o) {
+            return "TraversalOptionParent.Pick." + o.toString();
+        }
+
+        @Override
+        protected String getSyntax(final Number o) {
+            if (o instanceof Long)
+                return o + "L";
+            else if (o instanceof Double)
+                return o + "d";
+            else if (o instanceof Float)
+                return o + "f";
+            else if (o instanceof Integer)
+                return "(int) " + o;
+            else if (o instanceof Byte)
+                return "(byte) " + o;
+            if (o instanceof Short)
+                return "(short) " + o;
+            else if (o instanceof BigInteger)
+                return "new BigInteger('" + o.toString() + "')";
+            else if (o instanceof BigDecimal)
+                return "new BigDecimal('" + o.toString() + "')";
             else
-                return convertToString(o);
+                return o.toString();
         }
 
-        protected String convertToString(final Object object) {
-            if (object instanceof Bytecode.Binding)
-                return ((Bytecode.Binding) object).variable();
-            else if (object instanceof Bytecode)
-                return internalTranslate("__", (Bytecode) object);
-            else if (object instanceof Traversal)
-                return convertToString(((Traversal) object).asAdmin().getBytecode());
-            else if (object instanceof String) {
-                return (((String) object).contains("\"") ? "\"\"\"" + StringEscapeUtils.escapeJava((String) object) + "\"\"\"" : "\"" + StringEscapeUtils.escapeJava((String) object) + "\"")
-                        .replace("$", "\\$");
-            } else if (object instanceof Set) {
-                final Set<String> set = new HashSet<>(((Set) object).size());
-                for (final Object item : (Set) object) {
-                    set.add(convertToString(item));
-                }
-                return set.toString() + " as Set";
-            } else if (object instanceof List) {
-                final List<String> list = new ArrayList<>(((List) object).size());
-                for (final Object item : (List) object) {
-                    list.add(convertToString(item));
-                }
-                return list.toString();
-            } else if (object instanceof Map) {
-                final StringBuilder map = new StringBuilder("[");
-                for (final Map.Entry<?, ?> entry : ((Map<?, ?>) object).entrySet()) {
-                    map.append("(").
-                            append(convertToString(entry.getKey())).
-                            append("):(").
-                            append(convertToString(entry.getValue())).
-                            append("),");
-                }
-
-                // only need to remove this last bit if entries were added
-                if (!((Map<?, ?>) object).isEmpty())
-                    map.deleteCharAt(map.length() - 1);
-
-                return map.append("]").toString();
-            } else if (object instanceof Long)
-                return object + "L";
-            else if (object instanceof Double)
-                return object + "d";
-            else if (object instanceof Float)
-                return object + "f";
-            else if (object instanceof Integer)
-                return "(int) " + object;
-            else if (object instanceof Class)
-                return convertClassToString((Class<?>) object);
-            else if (object instanceof Timestamp)
-                return "new Timestamp(" + ((Timestamp) object).getTime() + ")";
-            else if (object instanceof Date)
-                return "new Date(" + ((Date) object).getTime() + ")";
-            else if (object instanceof UUID)
-                return "UUID.fromString('" + object.toString() + "')";
-            else if (object instanceof P)
-                return convertPToString((P) object, new StringBuilder()).toString();
-            else if (object instanceof SackFunctions.Barrier)
-                return "SackFunctions.Barrier." + object.toString();
-            else if (object instanceof VertexProperty.Cardinality)
-                return "VertexProperty.Cardinality." + object.toString();
-            else if (object instanceof TraversalOptionParent.Pick)
-                return "TraversalOptionParent.Pick." + object.toString();
-            else if (object instanceof Enum)
-                return ((Enum) object).getDeclaringClass().getSimpleName() + "." + object.toString();
-            else if (object instanceof Vertex) {
-                final Vertex vertex = (Vertex) object;
-                return "new ReferenceVertex(" +
-                        convertToString(vertex.id()) + "," +
-                        convertToString(vertex.label()) + ")";
-            } else if (object instanceof Edge) {
-                    final Edge edge = (Edge) object;
-                    return "new ReferenceEdge(" +
-                            convertToString(edge.id()) + "," +
-                            convertToString(edge.label()) + "," +
-                            "new ReferenceVertex(" + convertToString(edge.inVertex().id()) + "," +
-                            convertToString(edge.inVertex().label()) + ")," +
-                            "new ReferenceVertex(" + convertToString(edge.outVertex().id()) + "," +
-                            convertToString(edge.outVertex().label()) + "))";
-            } else if (object instanceof VertexProperty) {
-                    final VertexProperty<?> vertexProperty = (VertexProperty<?>) object;
-                    return "new ReferenceVertexProperty(" +
-                            convertToString(vertexProperty.id()) + "," +
-                            convertToString(vertexProperty.label()) + "," +
-                            convertToString(vertexProperty.value()) + ")";
-            } else if (object instanceof Lambda) {
-                final String lambdaString = ((Lambda) object).getLambdaScript().trim();
-                return lambdaString.startsWith("{") ? lambdaString : "{" + lambdaString + "}";
-            } else if (object instanceof TraversalStrategyProxy) {
-                final TraversalStrategyProxy proxy = (TraversalStrategyProxy) object;
-                final String className = convertClassToString(proxy.getStrategyClass());
-                if (proxy.getConfiguration().isEmpty())
-                    return className;
-                else
-                    return String.format("new %s(%s)", className, convertMapToArguments(ConfigurationConverter.getMap(proxy.getConfiguration())));
-            } else if (object instanceof TraversalStrategy) {
-                return convertToString(new TraversalStrategyProxy(((TraversalStrategy) object)));
-            } else
-                return null == object ? "null" : object.toString();
+        @Override
+        protected Script produceScript(final Set<?> o) {
+            return produceScript(new ArrayList<>(o)).append(" as Set");
         }
 
-        protected String internalTranslate(final String start, final Bytecode bytecode) {
-            final StringBuilder traversalScript = new StringBuilder(start);
-            for (final Bytecode.Instruction instruction : bytecode.getInstructions()) {
-                final String methodName = instruction.getOperator();
-                if (0 == instruction.getArguments().length)
-                    traversalScript.append(".").append(methodName).append("()");
-                else {
-                    traversalScript.append(".");
-                    String temp = methodName + "(";
+        @Override
+        protected Script produceScript(final List<?> o) {
+            final Iterator<?> iterator = ((List<?>) o).iterator();
+            script.append("[");
 
-                    for (final Object object : instruction.getArguments()) {
-                        temp = temp + convertToString(object) + ",";
-                    }
-
-                    traversalScript.append(temp.substring(0, temp.length() - 1)).append(")");
-                }
+            while (iterator.hasNext()) {
+                final Object nextItem = iterator.next();
+                convertToScript(nextItem);
+                if (iterator.hasNext())
+                    script.append(",").append(" ");
             }
-            return traversalScript.toString();
+
+            return script.append("]");
         }
 
-        protected StringBuilder convertPToString(final P p, final StringBuilder current) {
-            if (p instanceof TextP) return convertTextPToString((TextP) p, current);
-            if (p instanceof ConnectiveP) {
-                final List<P<?>> list = ((ConnectiveP) p).getPredicates();
-                for (int i = 0; i < list.size(); i++) {
-                    convertPToString(list.get(i), current);
-                    if (i < list.size() - 1)
-                        current.append(p instanceof OrP ? ".or(" : ".and(");
-                }
-                current.append(")");
-            } else
-                current.append("P.").append(p.getBiPredicate().toString()).append("(").append(convertToString(p.getValue())).append(")");
-            return current;
-        }
-
-        protected StringBuilder convertTextPToString(final TextP p, final StringBuilder current) {
-            current.append("TextP.").append(p.getBiPredicate().toString()).append("(").append(convertToString(p.getValue())).append(")");
-            return current;
+        @Override
+        protected Script produceScript(final Map<?, ?> o) {
+            script.append("[");
+            final Iterator<? extends Map.Entry<?, ?>> itty = ((Map<?, ?>) o).entrySet().iterator();
+            while (itty.hasNext()) {
+                final Map.Entry<?,?> entry = itty.next();
+                script.append("(");
+                convertToScript(entry.getKey());
+                script.append("):(");
+                convertToScript(entry.getValue());
+                script.append(")");
+                if (itty.hasNext())
+                    script.append(",");
+            }
+            return script.append("]");
         }
 
         /**
@@ -256,15 +240,131 @@
          * Those building custom {@link ScriptTranslator} instances might override this if they have other classes
          * that are not in {@link CoreImports} by default.
          */
-        protected String convertClassToString(final Class<?> clazz) {
-            return CoreImports.getClassImports().contains(clazz) ? clazz.getSimpleName() : clazz.getCanonicalName();
+        @Override
+        protected Script produceScript(final Class<?> o) {
+            return script.append(CoreImports.getClassImports().contains(o) ? o.getSimpleName() : o.getCanonicalName());
+        }
+
+        @Override
+        protected Script produceScript(final Enum<?> o) {
+            return script.append(o.getDeclaringClass().getSimpleName() + "." + o.toString());
+        }
+
+        @Override
+        protected Script produceScript(final Vertex o) {
+            script.append("new ReferenceVertex(");
+            convertToScript(o.id());
+            script.append(",");
+            convertToScript(o.label());
+            return script.append(")");
+        }
+
+        @Override
+        protected Script produceScript(final Edge o) {
+            script.append("new ReferenceEdge(");
+            convertToScript(o.id());
+            script.append(",");
+            convertToScript(o.label());
+            script.append(",new ReferenceVertex(");
+            convertToScript(o.inVertex().id());
+            script.append(",");
+            convertToScript(o.inVertex().label());
+            script.append("),new ReferenceVertex(");
+            convertToScript(o.outVertex().id());
+            script.append(",");
+            convertToScript(o.outVertex().label());
+            return script.append("))");
+        }
+
+        @Override
+        protected Script produceScript(final VertexProperty<?> o) {
+            script.append("new ReferenceVertexProperty(");
+            convertToScript(o.id());
+            script.append(",");
+            convertToScript(o.label());
+            script.append(",");
+            convertToScript(o.value());
+            return script.append(")");
+        }
+
+        @Override
+        protected Script produceScript(final TraversalStrategyProxy<?> o) {
+            if (o.getConfiguration().isEmpty()) {
+                return produceScript(o.getStrategyClass());
+            } else {
+                script.append("new ");
+                produceScript(o.getStrategyClass());
+                script.append("(");
+
+                final Iterator<Map.Entry<Object,Object>> itty = ConfigurationConverter.getMap(
+                        o.getConfiguration()).entrySet().iterator();
+                while (itty.hasNext()) {
+                    final Map.Entry<Object,Object> entry = itty.next();
+                    script.append(entry.getKey().toString());
+                    script.append(": ");
+                    convertToScript(entry.getValue());
+                    if (itty.hasNext()) script.append(", ");
+                }
+
+                return script.append(")");
+            }
+        }
+
+        @Override
+        protected Script produceScript(final String traversalSource, final Bytecode o) {
+            script.append(traversalSource);
+            for (final Bytecode.Instruction instruction : o.getInstructions()) {
+                final String methodName = instruction.getOperator();
+                if (0 == instruction.getArguments().length) {
+                    script.append(".").append(methodName).append("()");
+                } else {
+                    script.append(".").append(methodName).append("(");
+
+                    final Iterator<Object> itty = Arrays.stream(instruction.getArguments()).iterator();
+                    while(itty.hasNext()) {
+                        convertToScript(itty.next());
+                        if (itty.hasNext()) script.append(",");
+                    }
+
+                    script.append(")");
+                }
+            }
+            return script;
+        }
+
+        @Override
+        protected Script produceScript(final P<?> p) {
+            if (p instanceof TextP) {
+                script.append("TextP.").append(p.getBiPredicate().toString()).append("(");
+                convertToScript(p.getValue());
+            } else if (p instanceof ConnectiveP) {
+                // ConnectiveP gets some special handling because it's reduced to and(P, P, P) and we want it
+                // generated the way it was written which was P.and(P).and(P)
+                final List<P<?>> list = ((ConnectiveP) p).getPredicates();
+                final String connector = p instanceof OrP ? "or" : "and";
+                for (int i = 0; i < list.size(); i++) {
+                    produceScript(list.get(i));
+
+                    // for the first/last P there is no parent to close
+                    if (i > 0 && i < list.size() - 1) script.append(")");
+
+                    // add teh connector for all but last P
+                    if (i < list.size() - 1) {
+                        script.append(".").append(connector).append("(");
+                    }
+                }
+            } else {
+                script.append("P.").append(p.getBiPredicate().toString()).append("(");
+                convertToScript(p.getValue());
+            }
+            script.append(")");
+            return script;
         }
 
         private String convertMapToArguments(final Map<Object,Object> map) {
             return map.entrySet().stream().map(entry ->
-                String.format("%s: %s", entry.getKey().toString(), convertToString(entry.getValue()))).
+                String.format("%s: %s", entry.getKey().toString(), convertToScript(entry.getValue()))).
                     collect(Collectors.joining(", "));
         }
     }
 }
-
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslator.java
new file mode 100644
index 0000000..df427b4
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslator.java
@@ -0,0 +1,377 @@
+/*
+ *  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.translator;
+
+import org.apache.commons.configuration2.ConfigurationConverter;
+import org.apache.commons.text.StringEscapeUtils;
+import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
+import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
+import org.apache.tinkerpop.gremlin.process.traversal.Script;
+import org.apache.tinkerpop.gremlin.process.traversal.TextP;
+import org.apache.tinkerpop.gremlin.process.traversal.Translator;
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.TraversalStrategyProxy;
+import org.apache.tinkerpop.gremlin.process.traversal.util.ConnectiveP;
+import org.apache.tinkerpop.gremlin.process.traversal.util.OrP;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
+import org.apache.tinkerpop.gremlin.util.function.Lambda;
+
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.function.BinaryOperator;
+import java.util.function.Supplier;
+import java.util.function.UnaryOperator;
+
+/**
+ * Converts bytecode to a Javascript string of Gremlin.
+ *
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public final class JavascriptTranslator implements Translator.ScriptTranslator {
+
+    private final String traversalSource;
+    private final TypeTranslator typeTranslator;
+
+    private JavascriptTranslator(final String traversalSource, final TypeTranslator typeTranslator) {
+        this.traversalSource = traversalSource;
+        this.typeTranslator = typeTranslator;
+    }
+
+    /**
+     * Creates the translator with a {@code false} argument to {@code withParameters} using
+     * {@link #of(String, boolean)}.
+     */
+    public static JavascriptTranslator of(final String traversalSource) {
+        return of(traversalSource, false);
+    }
+
+    /**
+     * Creates the translator with the {@link DefaultTypeTranslator} passing the {@code withParameters} option to it
+     * which will handle type translation in a fashion that should typically increase cache hits and reduce
+     * compilation times if enabled at the sacrifice to rewriting of the script that could reduce readability.
+     */
+    public static JavascriptTranslator of(final String traversalSource, final boolean withParameters) {
+        return of(traversalSource, new DefaultTypeTranslator(withParameters));
+    }
+
+    /**
+     * Creates the translator with a custom {@link TypeTranslator} instance.
+     */
+    public static JavascriptTranslator of(final String traversalSource, final TypeTranslator typeTranslator) {
+        return new JavascriptTranslator(traversalSource, typeTranslator);
+    }
+
+    @Override
+    public Script translate(final Bytecode bytecode) {
+        return typeTranslator.apply(traversalSource, bytecode);
+    }
+
+    @Override
+    public String getTargetLanguage() {
+        return "gremlin-javascript";
+    }
+
+    @Override
+    public String toString() {
+        return StringFactory.translatorString(this);
+    }
+
+    @Override
+    public String getTraversalSource() {
+        return this.traversalSource;
+    }
+
+    /**
+     * Performs standard type translation for the TinkerPop types to Javascript.
+     */
+    public static class DefaultTypeTranslator extends AbstractTypeTranslator {
+
+        public DefaultTypeTranslator(final boolean withParameters) {
+            super(withParameters);
+        }
+
+        @Override
+        protected String getNullSyntax() {
+            return "null";
+        }
+
+        @Override
+        protected String getSyntax(final String o) {
+            return (o.contains("\"") ? "\"\"\"" + StringEscapeUtils.escapeJava(o) + "\"\"\"" : "\"" + StringEscapeUtils.escapeJava(o) + "\"")
+                    .replace("$", "\\$");
+        }
+
+        @Override
+        protected String getSyntax(final Boolean o) {
+            return o.toString();
+        }
+
+        @Override
+        protected String getSyntax(final Date o) {
+            return "new Date(" + o.getTime() + ")";
+        }
+
+        @Override
+        protected String getSyntax(final Timestamp o) {
+            return "new Date(" + o.getTime() + ")";
+        }
+
+        @Override
+        protected String getSyntax(final UUID o) {
+            return "'" + o.toString() + "'";
+        }
+
+        @Override
+        protected String getSyntax(final Lambda o) {
+            return "() => \"" + StringEscapeUtils.escapeEcmaScript(o.getLambdaScript().trim()) + "\"";
+        }
+
+        @Override
+        protected String getSyntax(final SackFunctions.Barrier o) {
+            return "Barrier." + o.toString();
+        }
+
+        @Override
+        protected String getSyntax(final VertexProperty.Cardinality o) {
+            return "Cardinality." + o.toString();
+        }
+
+        @Override
+        protected String getSyntax(final TraversalOptionParent.Pick o) {
+            return "Pick." + o.toString();
+        }
+
+        @Override
+        protected String getSyntax(final Number o) {
+            return o.toString();
+        }
+
+        @Override
+        protected Script produceScript(final Set<?> o) {
+            return produceScript(new ArrayList<>(o));
+        }
+
+        @Override
+        protected Script produceScript(final List<?> o) {
+            final Iterator<?> iterator = ((List<?>) o).iterator();
+            script.append("[");
+
+            while (iterator.hasNext()) {
+                final Object nextItem = iterator.next();
+                convertToScript(nextItem);
+                if (iterator.hasNext())
+                    script.append(",").append(" ");
+            }
+
+            return script.append("]");
+        }
+
+        @Override
+        protected Script produceScript(final Map<?, ?> o) {
+            script.append("new Map([");
+            final Iterator<? extends Map.Entry<?, ?>> itty = ((Map<?, ?>) o).entrySet().iterator();
+            while (itty.hasNext()) {
+                final Map.Entry<?,?> entry = itty.next();
+                script.append("[");
+                convertToScript(entry.getKey());
+                script.append(",");
+                convertToScript(entry.getValue());
+                script.append("]");
+                if (itty.hasNext())
+                    script.append(",");
+            }
+            return script.append("])");
+        }
+
+        @Override
+        protected Script produceScript(final Class<?> o) {
+            return script.append(o.getCanonicalName());
+        }
+
+        @Override
+        protected Script produceScript(final Enum<?> o) {
+            return script.append(o.getDeclaringClass().getSimpleName() + "." + o.toString());
+        }
+
+        @Override
+        protected Script produceScript(final Vertex o) {
+            script.append("new Vertex(");
+            convertToScript(o.id());
+            script.append(",");
+            convertToScript(o.label());
+            return script.append(", null)");
+        }
+
+        @Override
+        protected Script produceScript(final Edge o) {
+            script.append("new Edge(");
+            convertToScript(o.id());
+            script.append(", new Vertex(");
+            convertToScript(o.outVertex().id());
+            script.append(",");
+            convertToScript(o.outVertex().label());
+            script.append(", null),");
+            convertToScript(o.label());
+            script.append(", new Vertex(");
+            convertToScript(o.inVertex().id());
+            script.append(",");
+            convertToScript(o.inVertex().label());
+            return script.append(",null),null)");
+        }
+
+        @Override
+        protected Script produceScript(final VertexProperty<?> o) {
+            script.append("new Property(");
+            convertToScript(o.id());
+            script.append(",");
+            convertToScript(o.label());
+            script.append(",");
+            convertToScript(o.value());
+            script.append(",");
+            return script.append("null)");
+        }
+
+        @Override
+        protected Script produceScript(final TraversalStrategyProxy<?> o) {
+            if (o.getConfiguration().isEmpty()) {
+                return script.append("new " + o.getStrategyClass().getSimpleName() + "()");
+            } else {
+                script.append("new " + o.getStrategyClass().getSimpleName() + "(");
+                convertToScript(ConfigurationConverter.getMap(o.getConfiguration()));
+                return script.append(")");
+            }
+        }
+
+        @Override
+        protected Script produceScript(final String traversalSource, final Bytecode o) {
+            script.append(traversalSource);
+            for (final Bytecode.Instruction instruction : o.getInstructions()) {
+                final String methodName = instruction.getOperator();
+                if (0 == instruction.getArguments().length) {
+                    script.append(".").append(resolveSymbol(methodName)).append("()");
+                } else {
+                    script.append(".").append(resolveSymbol(methodName)).append("(");
+
+                    // have to special case withSack() for Groovy because UnaryOperator and BinaryOperator signatures
+                    // make it impossible for the interpreter to figure out which function to call. specifically we need
+                    // to discern between:
+                    //     withSack(A initialValue, UnaryOperator<A> splitOperator)
+                    //     withSack(A initialValue, BinaryOperator<A> splitOperator)
+                    // and:
+                    //     withSack(Supplier<A> initialValue, UnaryOperator<A> mergeOperator)
+                    //     withSack(Supplier<A> initialValue, BinaryOperator<A> mergeOperator)
+                    if (methodName.equals(TraversalSource.Symbols.withSack) &&
+                            instruction.getArguments().length == 2 && instruction.getArguments()[1] instanceof Lambda) {
+                        final String castFirstArgTo = instruction.getArguments()[0] instanceof Lambda ?
+                                Supplier.class.getName() : "";
+                        final Lambda secondArg = (Lambda) instruction.getArguments()[1];
+                        final String castSecondArgTo = secondArg.getLambdaArguments() == 1 ? UnaryOperator.class.getName() :
+                                BinaryOperator.class.getName();
+                        if (!castFirstArgTo.isEmpty())
+                            script.append(String.format("(%s) ", castFirstArgTo));
+                        convertToScript(instruction.getArguments()[0]);
+                        script.append(", (").append(castSecondArgTo).append(") ");
+                        convertToScript(instruction.getArguments()[1]);
+                        script.append(",");
+                    } else {
+                        for (final Object object : instruction.getArguments()) {
+                            convertToScript(object);
+                            script.append(",");
+                        }
+                    }
+                    script.setCharAtEnd(')');
+                }
+            }
+            return script;
+        }
+
+        @Override
+        protected Script produceScript(final P<?> p) {
+            if (p instanceof TextP) {
+                script.append("TextP.").append(p.getBiPredicate().toString()).append("(");
+                convertToScript(p.getValue());
+            } else if (p instanceof ConnectiveP) {
+                // ConnectiveP gets some special handling because it's reduced to and(P, P, P) and we want it
+                // generated the way it was written which was P.and(P).and(P)
+                final List<P<?>> list = ((ConnectiveP) p).getPredicates();
+                final String connector = p instanceof OrP ? "or" : "and";
+                for (int i = 0; i < list.size(); i++) {
+                    produceScript(list.get(i));
+
+                    // for the first/last P there is no parent to close
+                    if (i > 0 && i < list.size() - 1) script.append(")");
+
+                    // add teh connector for all but last P
+                    if (i < list.size() - 1) {
+                        script.append(".").append(connector).append("(");
+                    }
+                }
+            } else {
+                script.append("P.").append(p.getBiPredicate().toString()).append("(");
+                convertToScript(p.getValue());
+            }
+            script.append(")");
+            return script;
+        }
+
+        protected String resolveSymbol(final String methodName) {
+            return SymbolHelper.toJavascript(methodName);
+        }
+    }
+
+    static final class SymbolHelper {
+
+        private final static Map<String, String> TO_JS_MAP = new HashMap<>();
+        private final static Map<String, String> FROM_JS_MAP = new HashMap<>();
+
+        static {
+            TO_JS_MAP.put("from", "from_");
+            TO_JS_MAP.put("in", "in_");
+            TO_JS_MAP.put("with", "with_");
+            //
+            TO_JS_MAP.forEach((k, v) -> FROM_JS_MAP.put(v, k));
+        }
+
+        private SymbolHelper() {
+            // static methods only, do not instantiate
+        }
+
+        public static String toJavascript(final String symbol) {
+            return TO_JS_MAP.getOrDefault(symbol, symbol);
+        }
+
+        public static String toJava(final String symbol) {
+            return FROM_JS_MAP.getOrDefault(symbol, symbol);
+        }
+
+    }
+}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/PythonTranslator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/PythonTranslator.java
index 3e15bf1..63a1cbe 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/PythonTranslator.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/PythonTranslator.java
@@ -19,42 +19,37 @@
 
 package org.apache.tinkerpop.gremlin.process.traversal.translator;
 
-import org.apache.commons.configuration.ConfigurationConverter;
-import org.apache.commons.lang.StringEscapeUtils;
-import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.configuration2.ConfigurationConverter;
+import org.apache.commons.text.StringEscapeUtils;
 import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
-import org.apache.tinkerpop.gremlin.process.traversal.Operator;
 import org.apache.tinkerpop.gremlin.process.traversal.P;
 import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
+import org.apache.tinkerpop.gremlin.process.traversal.Script;
 import org.apache.tinkerpop.gremlin.process.traversal.TextP;
 import org.apache.tinkerpop.gremlin.process.traversal.Translator;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
-import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.TraversalStrategyProxy;
 import org.apache.tinkerpop.gremlin.process.traversal.util.ConnectiveP;
 import org.apache.tinkerpop.gremlin.process.traversal.util.OrP;
 import org.apache.tinkerpop.gremlin.structure.Edge;
-import org.apache.tinkerpop.gremlin.structure.Element;
-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.util.StringFactory;
 import org.apache.tinkerpop.gremlin.util.function.Lambda;
-import org.apache.tinkerpop.gremlin.util.iterator.ArrayIterator;
-import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 
 import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Collections;
+import java.math.BigDecimal;
+import java.sql.Timestamp;
+import java.util.Date;
 import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.UUID;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -66,26 +61,40 @@
  */
 public final class PythonTranslator implements Translator.ScriptTranslator {
 
-    private static final Set<String> STEP_NAMES = Stream.of(GraphTraversal.class.getMethods()).filter(method -> Traversal.class.isAssignableFrom(method.getReturnType())).map(Method::getName).collect(Collectors.toSet());
-    private static final Set<String> NO_STATIC = Stream.of(T.values(), Operator.values())
-            .flatMap(arg -> IteratorUtils.stream(new ArrayIterator<>(arg)))
-            .map(arg -> ((Enum) arg).name())
-            .collect(Collectors.toCollection(() -> new HashSet<>(Collections.singleton("not"))));
+    private static final Set<String> STEP_NAMES = Stream.of(GraphTraversal.class.getMethods()).filter(
+            method -> Traversal.class.isAssignableFrom(method.getReturnType())).map(Method::getName).
+            collect(Collectors.toSet());
 
     private final String traversalSource;
-    private final boolean importStatics;
+    private final TypeTranslator typeTranslator;
 
-    PythonTranslator(final String traversalSource, final boolean importStatics) {
+    private PythonTranslator(final String traversalSource, final TypeTranslator typeTranslator) {
         this.traversalSource = traversalSource;
-        this.importStatics = importStatics;
+        this.typeTranslator = typeTranslator;
     }
 
-    public static PythonTranslator of(final String traversalSource, final boolean importStatics) {
-        return new PythonTranslator(traversalSource, importStatics);
-    }
-
+    /**
+     * Creates the translator with a {@code false} argument to {@code withParameters} using
+     * {@link #of(String, boolean)}.
+     */
     public static PythonTranslator of(final String traversalSource) {
-        return new PythonTranslator(traversalSource, false);
+        return of(traversalSource, false);
+    }
+
+    /**
+     * Creates the translator with the {@link DefaultTypeTranslator} passing the {@code withParameters} option to it
+     * which will handle type translation in a fashion that should typically increase cache hits and reduce
+     * compilation times if enabled at the sacrifice to rewriting of the script that could reduce readability.
+     */
+    public static PythonTranslator of(final String traversalSource, final boolean withParameters) {
+        return of(traversalSource, new DefaultTypeTranslator(withParameters));
+    }
+
+    /**
+     * Creates the translator with a custom {@link TypeTranslator} instance.
+     */
+    public static PythonTranslator of(final String traversalSource, final TypeTranslator typeTranslator) {
+        return new PythonTranslator(traversalSource, typeTranslator);
     }
 
     @Override
@@ -94,8 +103,8 @@
     }
 
     @Override
-    public String translate(final Bytecode bytecode) {
-        return this.internalTranslate(this.traversalSource, bytecode);
+    public Script translate(final Bytecode bytecode) {
+        return typeTranslator.apply(traversalSource, bytecode);
     }
 
     @Override
@@ -110,165 +119,235 @@
 
     ///////
 
-    private String internalTranslate(final String start, final Bytecode bytecode) {
-        final StringBuilder traversalScript = new StringBuilder(start);
-        for (final Bytecode.Instruction instruction : bytecode.getInstructions()) {
-            final String methodName = instruction.getOperator();
-            final Object[] arguments = instruction.getArguments();
-            if (0 == arguments.length)
-                traversalScript.append(".").append(resolveSymbol(methodName)).append("()");
-            else if (methodName.equals("range") && 2 == arguments.length)
-                if (((Number) arguments[0]).longValue() + 1 == ((Number) arguments[1]).longValue())
-                    traversalScript.append("[").append(arguments[0]).append("]");
-                else
-                    traversalScript.append("[").append(arguments[0]).append(":").append(arguments[1]).append("]");
-            else if (methodName.equals("limit") && 1 == arguments.length)
-                traversalScript.append("[0:").append(arguments[0]).append("]");
-            else if (methodName.equals("values") && 1 == arguments.length && traversalScript.length() > 3 && !STEP_NAMES.contains(arguments[0].toString()))
-                traversalScript.append(".").append(arguments[0]);
-            else {
-                traversalScript.append(".");
-                String temp = resolveSymbol(methodName) + "(";
+    /**
+     * Performs standard type translation for the TinkerPop types to Python.
+     */
+    public static class DefaultTypeTranslator extends AbstractTypeTranslator {
 
-                // jython has trouble with java varargs...wrapping in collection seems to solve the problem
-                final boolean varargsBeware = instruction.getOperator().equals(TraversalSource.Symbols.withStrategies)
-                        || instruction.getOperator().equals(TraversalSource.Symbols.withoutStrategies);
-                if (varargsBeware) temp = temp + "[";
-
-                for (final Object object : arguments) {
-                    temp = temp + convertToString(object) + ",";
-                }
-                temp = temp.substring(0, temp.length() - 1);
-
-                if (varargsBeware) temp = temp + "]";
-
-                traversalScript.append(temp).append(")");
-            }
-            // clip off __.
-            if (this.importStatics && traversalScript.substring(0, 3).startsWith("__.")
-                    && !NO_STATIC.stream().filter(name -> traversalScript.substring(3).startsWith(resolveSymbol(name))).findAny().isPresent()) {
-                traversalScript.delete(0, 3);
-            }
+        public DefaultTypeTranslator(final boolean withParameters) {
+            super(withParameters);
         }
-        return traversalScript.toString();
-    }
 
-    protected String convertToString(final Object object) {
-        if (object instanceof Bytecode.Binding)
-            return ((Bytecode.Binding) object).variable();
-        else if (object instanceof Bytecode)
-            return this.internalTranslate("__", (Bytecode) object);
-        else if (object instanceof Traversal)
-            return convertToString(((Traversal) object).asAdmin().getBytecode());
-        else if (object instanceof String)
-            return ((String) object).contains("'") || ((String) object).contains(System.lineSeparator()) ?
-                    "\"\"\"" + object + "\"\"\"" : "'" + object + "'";
-        else if (object instanceof Set) {
-            final Set<String> set = new LinkedHashSet<>(((Set) object).size());
-            for (final Object item : (Set) object) {
-                set.add(convertToString(item));
-            }
-            return "set(" + set.toString() + ")";
-        } else if (object instanceof List) {
-            final List<String> list = new ArrayList<>(((List) object).size());
-            for (final Object item : (List) object) {
-                list.add(convertToString(item));
-            }
-            return list.toString();
-        } else if (object instanceof Map) {
-            final StringBuilder map = new StringBuilder("{");
-            for (final Map.Entry<?, ?> entry : ((Map<?, ?>) object).entrySet()) {
-                map.append(convertToString(entry.getKey())).
-                        append(":").
-                        append(convertToString(entry.getValue())).
-                        append(",");
-            }
-            return map.length() > 1 ? map.substring(0, map.length() - 1) + "}" : map.append("}").toString();
-        } else if (object instanceof Long)
-            return object + "L";
-        else if (object instanceof TraversalStrategyProxy) {
-            return resolveTraversalStrategyProxy((TraversalStrategyProxy) object);
-        } else if (object instanceof TraversalStrategy) {
-            return convertToString(new TraversalStrategyProxy((TraversalStrategy) object));
-        } else if (object instanceof Boolean)
-            return object.equals(Boolean.TRUE) ? "True" : "False";
-        else if (object instanceof Class)
-            return ((Class) object).getCanonicalName();
-        else if (object instanceof VertexProperty.Cardinality)
-            return "Cardinality." + resolveSymbol(object.toString());
-        else if (object instanceof SackFunctions.Barrier)
-            return "Barrier." + resolveSymbol(object.toString());
-        else if (object instanceof TraversalOptionParent.Pick)
-            return "Pick." + resolveSymbol(object.toString());
-        else if (object instanceof Enum)
-            return convertStatic(((Enum) object).getDeclaringClass().getSimpleName() + ".") + resolveSymbol(object.toString());
-        else if (object instanceof P)
-            return convertPToString((P) object, new StringBuilder()).toString();
-        else if (object instanceof Element) {
-            if (object instanceof Vertex) {
-                final Vertex vertex = (Vertex) object;
-                return "Vertex(" + convertToString(vertex.id()) + "," + convertToString(vertex.label()) + ")";
-            } else if (object instanceof Edge) {
-                final Edge edge = (Edge) object;
-                return "Edge(" + convertToString(edge.id()) + "," +
-                        convertToString(edge.outVertex()) + "," +
-                        convertToString(edge.label()) + "," +
-                        convertToString(edge.inVertex()) + ")";
-            } else {
-                final VertexProperty vertexProperty = (VertexProperty) object;
-                return "VertexProperty(" + convertToString(vertexProperty.id()) + "," +
-                        convertToString(vertexProperty.label()) + "," +
-                        convertToString(vertexProperty.value()) + ")";
-            }
-        } else if (object instanceof Lambda)
-            return convertLambdaToString((Lambda) object);
-        else
-            return null == object ? "None" : object.toString();
-    }
+        @Override
+        protected String getNullSyntax() {
+            return "None";
+        }
 
-    private String convertStatic(final String name) {
-        return this.importStatics ? "" : name;
-    }
+        @Override
+        protected String getSyntax(final String o) {
+            return o.contains("'") || o.contains(System.lineSeparator()) ?
+                    "\"\"\"" + o + "\"\"\"" : "'" + o + "'";
+        }
 
-    private StringBuilder convertPToString(final P p, final StringBuilder current) {
-        if (p instanceof TextP) return convertTextPToString((TextP) p, current);
-        if (p instanceof ConnectiveP) {
-            final List<P<?>> list = ((ConnectiveP) p).getPredicates();
-            for (int i = 0; i < list.size(); i++) {
-                convertPToString(list.get(i), current);
-                if (i < list.size() - 1)
-                    current.append(p instanceof OrP ? ".or_(" : ".and_(");
-            }
-            current.append(")");
-        } else
-            current.append(convertStatic("P.")).append(p.getBiPredicate().toString()).append("(").append(convertToString(p.getValue())).append(")");
-        return current;
-    }
+        @Override
+        protected String getSyntax(final Boolean o) {
+            return o ? "True" : "False";
+        }
 
-    private StringBuilder convertTextPToString(final TextP p, final StringBuilder current) {
-        current.append(convertStatic("TextP.")).append(p.getBiPredicate().toString()).append("(").append(convertToString(p.getValue())).append(")");
-        return current;
-    }
+        @Override
+        protected String getSyntax(final Date o) {
+            return "datetime.datetime.utcfromtimestamp(" + o.getTime() + " / 1000.0)";
+        }
 
-    protected String convertLambdaToString(final Lambda lambda) {
-        final String lambdaString = lambda.getLambdaScript().trim();
-        if (lambda.getLambdaLanguage().equalsIgnoreCase("gremlin-python")) {
-            return lambdaString.startsWith("lambda") ? lambdaString : "lambda: \"" + lambdaString + "\"";
-        } else {
-            // gremlin-groovy
+        @Override
+        protected String getSyntax(final Timestamp o) {
+            return "timestamp(" + o.getTime() + " / 1000.0)";
+        }
+
+        @Override
+        protected String getSyntax(final UUID o) {
+            return "UUID('" + o.toString() +"')";
+        }
+
+        @Override
+        protected String getSyntax(final Lambda o) {
+            final String lambdaString = o.getLambdaScript().trim();
             return "lambda: \"" + StringEscapeUtils.escapeJava(lambdaString) + "\"";
         }
-    }
 
-    protected String resolveSymbol(final String methodName) {
-        return SymbolHelper.toPython(methodName);
-    }
+        @Override
+        protected String getSyntax(final Number o) {
+            // todo: nan/inf
+            // all int/short/BigInteger/long are just python int/bignum
+            if (o instanceof Double || o instanceof Float || o instanceof BigDecimal)
+                return "float(" + o + ")";
+            else if (o instanceof Byte)
+                return "SingleByte(" + o + ")";
+            else
+                return o.toString();
+        }
 
-    protected String resolveTraversalStrategyProxy(final TraversalStrategyProxy proxy) {
-        if (proxy.getConfiguration().isEmpty())
-            return "TraversalStrategy('" + proxy.getStrategyClass().getSimpleName() + "')";
-        else
-            return "TraversalStrategy('" + proxy.getStrategyClass().getSimpleName() + "'," + convertToString(ConfigurationConverter.getMap(proxy.getConfiguration())) + ")";
+        @Override
+        protected String getSyntax(final SackFunctions.Barrier o) {
+            return "Barrier." + resolveSymbol(o.toString());
+        }
+
+        @Override
+        protected String getSyntax(final VertexProperty.Cardinality o) {
+            return "Cardinality." + resolveSymbol(o.toString());
+        }
+
+        @Override
+        protected String getSyntax(final TraversalOptionParent.Pick o) {
+            return "Pick." + resolveSymbol(o.toString());
+        }
+
+        @Override
+        protected Script produceScript(final Set<?> o) {
+            final Iterator<?> iterator = o.iterator();
+            script.append("set(");
+            while(iterator.hasNext()) {
+                convertToScript(iterator.next());
+                if (iterator.hasNext())
+                    script.append(",");
+            }
+            return script.append(")");
+        }
+
+        @Override
+        protected Script produceScript(final List<?> o) {
+            final Iterator<?> iterator = o.iterator();
+            script.append("[");
+            while(iterator.hasNext()) {
+                convertToScript(iterator.next());
+                if (iterator.hasNext())
+                    script.append(",");
+            }
+            return script.append("]");
+        }
+
+        @Override
+        protected Script produceScript(final Map<?, ?> o) {
+            script.append("{");
+            final Iterator<? extends Map.Entry<?, ?>> itty = o.entrySet().iterator();
+            while (itty.hasNext()) {
+                final Map.Entry<?,?> entry = itty.next();
+                convertToScript(entry.getKey()).append(":");
+                convertToScript(entry.getValue());
+                if (itty.hasNext())
+                    script.append(",");
+            }
+            return script.append("}");
+        }
+
+        @Override
+        protected Script produceScript(final Class<?> o) {
+            return script.append("GremlinType(" + o.getCanonicalName() + ")");
+        }
+
+        @Override
+        protected Script produceScript(final Enum<?> o) {
+            return script.append(o.getDeclaringClass().getSimpleName() + "." + resolveSymbol(o.toString()));
+        }
+
+        @Override
+        protected Script produceScript(final Vertex o) {
+            script.append("Vertex(");
+            convertToScript(o.id()).append(",");
+            return convertToScript(o.label()).append(")");
+        }
+
+        @Override
+        protected Script produceScript(final Edge o) {
+            script.append("Edge(");
+            convertToScript(o.id()).append(",");
+            convertToScript(o.outVertex()).append(",");
+            convertToScript(o.label()).append(",");
+            return convertToScript(o.inVertex()).append(")");
+        }
+
+        @Override
+        protected Script produceScript(final VertexProperty<?> o) {
+            script.append("VertexProperty(");
+            convertToScript(o.id()).append(",");
+            convertToScript(o.label()).append(",");
+            return convertToScript(o.value()).append(")");
+        }
+
+        @Override
+        protected Script produceScript(final TraversalStrategyProxy<?> o) {
+            if (o.getConfiguration().isEmpty())
+                return script.append("TraversalStrategy('" + o.getStrategyClass().getSimpleName() + "', None, '" + o.getStrategyClass().getName() + "')");
+            else {
+                script.append("TraversalStrategy('").append(o.getStrategyClass().getSimpleName()).append("',");
+                convertToScript(ConfigurationConverter.getMap(o.getConfiguration()));
+                script.append(", '");
+                script.append(o.getStrategyClass().getName());
+                return script.append("')");
+            }
+        }
+
+        @Override
+        protected Script produceScript(final String traversalSource, final Bytecode o) {
+            script.append(traversalSource);
+            for (final Bytecode.Instruction instruction : o.getInstructions()) {
+                final String methodName = instruction.getOperator();
+                final Object[] arguments = instruction.getArguments();
+                if (0 == arguments.length)
+                    script.append(".").append(resolveSymbol(methodName)).append("()");
+                else if (methodName.equals("range") && 2 == arguments.length)
+                    if (((Number) arguments[0]).longValue() + 1 == ((Number) arguments[1]).longValue())
+                        script.append("[").append(arguments[0].toString()).append("]");
+                    else
+                        script.append("[").append(arguments[0].toString()).append(":").append(arguments[1].toString()).append("]");
+                else if (methodName.equals("limit") && 1 == arguments.length)
+                    script.append("[0:").append(arguments[0].toString()).append("]");
+                else if (methodName.equals("values") && 1 == arguments.length && script.getScript().length() > 3 && !STEP_NAMES.contains(arguments[0].toString()))
+                    script.append(".").append(arguments[0].toString());
+                else {
+                    script.append(".").append(resolveSymbol(methodName)).append("(");
+
+                    // python has trouble with java varargs...wrapping in collection seems to solve the problem
+                    final boolean varargsBeware = instruction.getOperator().equals(TraversalSource.Symbols.withStrategies)
+                            || instruction.getOperator().equals(TraversalSource.Symbols.withoutStrategies);
+                    if (varargsBeware) script.append("*[");
+
+                    final Iterator<?> itty = Stream.of(arguments).iterator();
+                    while (itty.hasNext()) {
+                        convertToScript(itty.next());
+                        if (itty.hasNext()) script.append(",");
+                    }
+
+                    if (varargsBeware) script.append("]");
+
+                    script.append(")");
+                }
+            }
+            return script;
+        }
+
+        @Override
+        protected Script produceScript(final P<?> p) {
+            if (p instanceof TextP) {
+                script.append("TextP.").append(resolveSymbol(p.getBiPredicate().toString())).append("(");
+                convertToScript(p.getValue());
+            } else if (p instanceof ConnectiveP) {
+                // ConnectiveP gets some special handling because it's reduced to and(P, P, P) and we want it
+                // generated the way it was written which was P.and(P).and(P)
+                final List<P<?>> list = ((ConnectiveP) p).getPredicates();
+                final String connector = p instanceof OrP ? "or_" : "and_";
+                for (int i = 0; i < list.size(); i++) {
+                    produceScript(list.get(i));
+
+                    // for the first/last P there is no parent to close
+                    if (i > 0 && i < list.size() - 1) script.append(")");
+
+                    // add teh connector for all but last P
+                    if (i < list.size() - 1) {
+                        script.append(".").append(connector).append("(");
+                    }
+                }
+            } else {
+                script.append("P.").append(resolveSymbol(p.getBiPredicate().toString())).append("(");
+                convertToScript(p.getValue());
+            }
+            script.append(")");
+            return script;
+        }
+
+        protected String resolveSymbol(final String methodName) {
+            return SymbolHelper.toPython(methodName);
+        }
     }
 
     static final class SymbolHelper {
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_O_S_SE_SL_Traverser.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_O_S_SE_SL_Traverser.java
index 33c5520..57fa47a 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_O_S_SE_SL_Traverser.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_O_S_SE_SL_Traverser.java
@@ -136,7 +136,7 @@
 
     protected final boolean equals(final B_O_S_SE_SL_Traverser other) {
         return super.equals(other) && other.loops == this.loops
-                && (this.loopName != null ? this.loopName.equals(other.loopName) : other.loopName == null)
+                && Objects.equals(this.loopName, other.loopName)
                 && !carriesUnmergeableSack();
     }
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/AbstractTraverser.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/AbstractTraverser.java
index 658ba4b..e76016a 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/AbstractTraverser.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/AbstractTraverser.java
@@ -27,6 +27,7 @@
 import org.apache.tinkerpop.gremlin.structure.util.Attachable;
 import org.apache.tinkerpop.gremlin.structure.util.reference.ReferenceFactory;
 
+import java.util.Objects;
 import java.util.Set;
 import java.util.function.Function;
 
@@ -203,16 +204,16 @@
 
     @Override
     public int hashCode() {
-        return this.t.hashCode();
+        return Objects.hashCode(this.t);
     }
 
     @Override
     public boolean equals(final Object object) {
-        return object instanceof AbstractTraverser && ((AbstractTraverser) object).get().equals(this.t);
+        return object instanceof AbstractTraverser && Objects.equals(this.t, ((AbstractTraverser) object).t);
     }
 
     @Override
     public String toString() {
-        return this.t.toString();
+        return Objects.toString(this.t);
     }
 }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/EmptyTraverser.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/EmptyTraverser.java
index 3aeafbd..c68fdc6 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/EmptyTraverser.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/EmptyTraverser.java
@@ -20,6 +20,7 @@
 
 import org.apache.tinkerpop.gremlin.process.traversal.Path;
 import org.apache.tinkerpop.gremlin.process.traversal.Step;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalSideEffects;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.EmptyPath;
@@ -30,12 +31,18 @@
 import java.util.function.Function;
 
 /**
+ * A {@link Traverser} with no bulk which effectively means that it will no longer be propagated through a
+ * {@link Traversal}.
+ *
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
 public final class EmptyTraverser<T> implements Traverser<T>, Traverser.Admin<T> {
 
     private static final EmptyTraverser INSTANCE = new EmptyTraverser();
 
+    /**
+     * The empty {@link Traverser} instance.
+     */
     public static <R> EmptyTraverser<R> instance() {
         return INSTANCE;
     }
@@ -95,7 +102,7 @@
     }
 
     @Override
-    public void setBulk(long count) {
+    public void setBulk(final long count) {
 
     }
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/TraverserSet.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/TraverserSet.java
index 52bf4d8..023a73c 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/TraverserSet.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/TraverserSet.java
@@ -32,6 +32,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Queue;
+import java.util.Random;
 import java.util.Set;
 import java.util.Spliterator;
 
@@ -153,10 +154,10 @@
         list.forEach(traverser -> this.map.put(traverser, traverser));
     }
 
-    public void shuffle() {
+    public void shuffle(final Random random) {
         final List<Traverser.Admin<S>> list = new ArrayList<>(this.map.size());
         IteratorUtils.removeOnNext(this.map.values().iterator()).forEachRemaining(list::add);
-        Collections.shuffle(list);
+        Collections.shuffle(list, random);
         this.map.clear();
         list.forEach(traverser -> this.map.put(traverser, traverser));
     }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/BytecodeHelper.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/BytecodeHelper.java
index d02c152..9303be1 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/BytecodeHelper.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/BytecodeHelper.java
@@ -20,6 +20,7 @@
 package org.apache.tinkerpop.gremlin.process.traversal.util;
 
 import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
+import org.apache.tinkerpop.gremlin.process.traversal.GraphOp;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
 import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedFactory;
@@ -31,6 +32,7 @@
 import java.util.List;
 import java.util.Optional;
 import java.util.function.Predicate;
+import java.util.stream.Stream;
 
 /**
  * Utility class for parsing {@link Bytecode}.
@@ -45,7 +47,7 @@
     }
 
     /**
-     * Parses {@link Bytecode} to find {@link TraversalStrategy} objects in the source instructions.
+     * Parses {@link Bytecode} to find {@link TraversalStrategy} objects added in the source instructions.
      */
     public static <A extends TraversalStrategy> Iterator<A> findStrategies(final Bytecode bytecode, final Class<A> clazz) {
         return IteratorUtils.map(
@@ -67,6 +69,13 @@
         return clone;
     }
 
+    /**
+     * Checks if the bytecode is one of the standard {@link GraphOp} options.
+     */
+    public static boolean isGraphOperation(final Bytecode bytecode) {
+        return Stream.of(GraphOp.values()).anyMatch(op -> op.equals(bytecode));
+    }
+
     public static Optional<String> getLambdaLanguage(final Bytecode bytecode) {
         for (final Bytecode.Instruction instruction : bytecode.getInstructions()) {
             for (Object object : instruction.getArguments()) {
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/BytecodeUtil.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/BytecodeUtil.java
deleted file mode 100644
index 1b099d3..0000000
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/BytecodeUtil.java
+++ /dev/null
@@ -1,49 +0,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.
- */
-package org.apache.tinkerpop.gremlin.process.traversal.util;
-
-import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
-import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
-import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
-import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
-
-import java.util.Iterator;
-
-/**
- * Utility class for parsing {@link Bytecode}.
- *
- * @author Stephen Mallette (http://stephen.genoprime.com)
- * @deprecated As of release 3.4.9, replaced by {@link BytecodeHelper}.
- */
-public final class BytecodeUtil {
-
-    private BytecodeUtil() {}
-
-    /**
-     * Parses {@link Bytecode} to find {@link TraversalStrategy} objects in the source instructions.
-     * @deprecated As of release 3.4.9, replaced by {@link BytecodeHelper#findStrategies(Bytecode, Class)}.
-     */
-    @Deprecated
-    public static <A extends TraversalStrategy> Iterator<A> findStrategies(final Bytecode bytecode, final Class<A> clazz) {
-        return IteratorUtils.map(
-                IteratorUtils.filter(bytecode.getSourceInstructions().iterator(),
-                        s -> s.getOperator().equals(TraversalSource.Symbols.withStrategies) && clazz.isAssignableFrom(s.getArguments()[0].getClass())),
-                os -> (A) os.getArguments()[0]);
-    }
-}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/DefaultTraversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/DefaultTraversal.java
index cd3b7c4..ea5cb33 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/DefaultTraversal.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/DefaultTraversal.java
@@ -18,12 +18,14 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.util;
 
+import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.VertexProgramStep;
 import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
 import org.apache.tinkerpop.gremlin.process.traversal.Step;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalSideEffects;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import org.apache.tinkerpop.gremlin.process.traversal.TraverserGenerator;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
@@ -89,8 +91,6 @@
         steps.addAll(traversal.getSteps());
     }
 
-    // TODO: clean up unused or redundant constructors
-
     public DefaultTraversal() {
         this(EmptyGraph.instance(), TraversalStrategies.GlobalCache.getStrategies(EmptyGraph.class), new Bytecode());
     }
@@ -111,7 +111,7 @@
     @Override
     public TraverserGenerator getTraverserGenerator() {
         if (null == this.generator)
-            this.generator = (this.parent instanceof EmptyStep) ?
+            this.generator = isRoot() ?
                     DefaultTraverserGeneratorFactory.instance().getTraverserGenerator(this.getTraverserRequirements()) :
                     TraversalHelper.getRootTraversal(this).getTraverserGenerator();
         return this.generator;
@@ -121,34 +121,54 @@
     public void applyStrategies() throws IllegalStateException {
         if (this.locked) throw Traversal.Exceptions.traversalIsLocked();
         TraversalHelper.reIdSteps(this.stepPosition, this);
-        this.strategies.applyStrategies(this);
-        boolean hasGraph = null != this.graph;
-        for (int i = 0, j = this.steps.size(); i < j; i++) { // "foreach" can lead to ConcurrentModificationExceptions
-            final Step step = this.steps.get(i);
-            if (step instanceof TraversalParent) {
-                for (final Traversal.Admin<?, ?> globalChild : ((TraversalParent) step).getGlobalChildren()) {
-                    globalChild.setStrategies(this.strategies);
-                    globalChild.setSideEffects(this.sideEffects);
-                    if (hasGraph) globalChild.setGraph(this.graph);
-                    globalChild.applyStrategies();
-                }
-                for (final Traversal.Admin<?, ?> localChild : ((TraversalParent) step).getLocalChildren()) {
-                    localChild.setStrategies(this.strategies);
-                    localChild.setSideEffects(this.sideEffects);
-                    if (hasGraph) localChild.setGraph(this.graph);
-                    localChild.applyStrategies();
-                }
+        final boolean hasGraph = null != this.graph;
+
+        // we only want to apply strategies on the top-level step or if we got some graphcomputer stuff going on.
+        // seems like in that case, the "top-level" of the traversal is really held by the VertexProgramStep which
+        // needs to have strategies applied on "pure" copies of the traversal it is holding (i think). it further
+        // seems that we need three recursions over the traversal hierarchy to ensure everything "works", where
+        // strategy application requires top-level strategies and side-effects pushed into each child and then after
+        // application of the strategies we need to call applyStrategies() on all the children to ensure that their
+        // steps get reId'd and traverser requirements are set.
+        if (isRoot() || this.getParent() instanceof VertexProgramStep) {
+
+            // note that prior to applying strategies to children we used to set side-effects and strategies of all
+            // children to that of the parent. under this revised model of strategy application from TINKERPOP-1568
+            // it doesn't appear to be necessary to do that (at least from the perspective of the test suite). by,
+            // moving side-effect setting after actual recursive strategy application we save a loop and by
+            // consequence also fix a problem where strategies might reset something in sideeffects which seems to
+            // happen in TranslationStrategy.
+            final Iterator<TraversalStrategy<?>> strategyIterator = this.strategies.iterator();
+            while (strategyIterator.hasNext()) {
+                final TraversalStrategy<?> strategy = strategyIterator.next();
+                TraversalHelper.applyTraversalRecursively(strategy::apply, this);
             }
+
+            // don't need to re-apply strategies to "this" - leads to endless recursion in GraphComputer.
+            TraversalHelper.applyTraversalRecursively(t -> {
+                if (hasGraph) t.setGraph(this.graph);
+                if(!(t.isRoot()) && t != this && !t.isLocked()) {
+                    t.setStrategies(new DefaultTraversalStrategies());
+                    t.setSideEffects(this.sideEffects);
+                    t.applyStrategies();
+                }
+            }, this);
         }
+        
         this.finalEndStep = this.getEndStep();
+
         // finalize requirements
-        if (this.getParent() instanceof EmptyStep) {
-            this.requirements = null;
-            this.getTraverserRequirements();
+        if (this.isRoot()) {
+            resetTraverserRequirements();
         }
         this.locked = true;
     }
 
+    private void resetTraverserRequirements() {
+        this.requirements = null;
+        this.getTraverserRequirements();
+    }
+
     @Override
     public Set<TraverserRequirement> getTraverserRequirements() {
         if (null == this.requirements) {
@@ -186,7 +206,7 @@
                 return this.finalEndStep.next();
             }
         } catch (final FastNoSuchElementException e) {
-            throw this.parent instanceof EmptyStep ? new NoSuchElementException() : e;
+            throw this.isRoot() ? new NoSuchElementException() : e;
         }
     }
 
@@ -209,7 +229,7 @@
             // and release the resources.
             CloseableIterator.closeIterator(this);
 
-            throw this.parent instanceof EmptyStep ? new NoSuchElementException() : e;
+            throw this.isRoot() ? new NoSuchElementException() : e;
         }
     }
 
@@ -326,7 +346,7 @@
 
     @Override
     public void setParent(final TraversalParent step) {
-        this.parent = step;
+        this.parent = null == step ? EmptyStep.instance() : step;
     }
 
     @Override
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/DefaultTraversalStrategies.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/DefaultTraversalStrategies.java
index 9667137..b246f81 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/DefaultTraversalStrategies.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/DefaultTraversalStrategies.java
@@ -18,13 +18,13 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.util;
 
-import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Iterator;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Optional;
@@ -41,7 +41,8 @@
     @SuppressWarnings({"unchecked", "varargs"})
     public TraversalStrategies addStrategies(final TraversalStrategy<?>... strategies) {
         for (final TraversalStrategy<?> addStrategy : strategies) {
-            this.traversalStrategies.remove(addStrategy);
+            // search by class to prevent strategies from being added more than once
+            getStrategy(addStrategy.getClass()).ifPresent(s -> this.traversalStrategies.remove(s));
         }
         Collections.addAll(this.traversalStrategies, strategies);
         this.traversalStrategies = TraversalStrategies.sortStrategies(this.traversalStrategies);
@@ -70,6 +71,11 @@
     }
 
     @Override
+    public Iterator<TraversalStrategy<?>> iterator() {
+        return this.traversalStrategies.iterator();
+    }
+
+    @Override
     public <T extends TraversalStrategy> Optional<T> getStrategy(final Class<T> traversalStrategyClass) {
         for (final TraversalStrategy<?> traversalStrategy : this.traversalStrategies) {
             if (traversalStrategyClass.isAssignableFrom(traversalStrategy.getClass()))
@@ -77,17 +83,6 @@
         }
         return Optional.empty();
     }
-    /**
-     * @deprecated As of release 3.3.10, not directly replaced as this mode of strategy application has not been
-     * utilized since early days of 3.x
-     */
-    @Override
-    @Deprecated
-    public void applyStrategies(final Traversal.Admin<?, ?> traversal) {
-        for (final TraversalStrategy<?> traversalStrategy : this.traversalStrategies) {
-            traversalStrategy.apply(traversal);
-        }
-    }
 
     @Override
     public DefaultTraversalStrategies clone() {
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/EmptyTraversalStrategies.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/EmptyTraversalStrategies.java
index 127df4d..f99d4bc 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/EmptyTraversalStrategies.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/EmptyTraversalStrategies.java
@@ -18,14 +18,11 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.util;
 
-import org.apache.tinkerpop.gremlin.process.traversal.Translator;
-import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
-import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserGeneratorFactory;
-import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.DefaultTraverserGeneratorFactory;
 
 import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
 
 /**
@@ -43,9 +40,10 @@
         return Collections.emptyList();
     }
 
-    @Override
-    public void applyStrategies(final Traversal.Admin<?, ?> traversal) {
 
+    @Override
+    public Iterator<TraversalStrategy<?>> iterator() {
+        return toList().iterator();
     }
 
     @Override
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/PathUtil.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/PathUtil.java
index cefc62a..8dafa5d 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/PathUtil.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/PathUtil.java
@@ -58,7 +58,6 @@
                 }
             }
             referencedLabels.addAll(labels);
-
         }
 
         return referencedLabels;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/PureTraversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/PureTraversal.java
index 682f0d2..e28bcd4 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/PureTraversal.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/PureTraversal.java
@@ -19,7 +19,7 @@
 
 package org.apache.tinkerpop.gremlin.process.traversal.util;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.process.computer.util.VertexProgramHelper;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.structure.Graph;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalExplanation.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalExplanation.java
index 2376ecb..c99dd85 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalExplanation.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalExplanation.java
@@ -51,8 +51,8 @@
 
     public TraversalExplanation(final Traversal.Admin<?, ?> traversal) {
         this.traversal = traversal.clone();
-        TraversalStrategies mutatingStrategies = new DefaultTraversalStrategies();
-        for (final TraversalStrategy strategy : this.traversal.getStrategies().toList()) {
+        final TraversalStrategies mutatingStrategies = new DefaultTraversalStrategies();
+        for (final TraversalStrategy strategy : this.traversal.getStrategies()) {
             final Traversal.Admin<?, ?> mutatingTraversal = this.traversal.clone();
             mutatingStrategies.addStrategies(strategy);
             mutatingTraversal.setStrategies(mutatingStrategies);
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
index 21319f5..4e7eb92 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
@@ -23,7 +23,7 @@
 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.lambda.ElementValueTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.lambda.ValueTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.lambda.TokenTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.step.ByModulating;
 import org.apache.tinkerpop.gremlin.process.traversal.step.HasContainerHolder;
@@ -98,7 +98,7 @@
 
     private static char isLocalStarGraph(final Traversal.Admin<?, ?> traversal, char state) {
         if (state == 'u' &&
-                (traversal instanceof ElementValueTraversal ||
+                (traversal instanceof ValueTraversal ||
                         (traversal instanceof TokenTraversal && !((TokenTraversal) traversal).getToken().equals(T.id))))
             return 'x';
         for (final Step step : traversal.getSteps()) {
@@ -116,7 +116,7 @@
                 }
             } else if (step instanceof TraversalParent) {
                 final char currState = state;
-                Set<Character> states = new HashSet<>();
+                final Set<Character> states = new HashSet<>();
                 for (final Traversal.Admin<?, ?> local : ((TraversalParent) step).getLocalChildren()) {
                     final char s = isLocalStarGraph(local, currState);
                     if ('x' == s) return 'x';
@@ -290,7 +290,7 @@
     }
 
     public static boolean isGlobalChild(Traversal.Admin<?, ?> traversal) {
-        while (!(traversal.getParent() instanceof EmptyStep)) {
+        while (!(traversal.isRoot())) {
             if (traversal.getParent().getLocalChildren().contains(traversal))
                 return false;
             traversal = traversal.getParent().asStep().getTraversal();
@@ -465,7 +465,11 @@
      */
     public static void applyTraversalRecursively(final Consumer<Traversal.Admin<?, ?>> consumer, final Traversal.Admin<?, ?> traversal) {
         consumer.accept(traversal);
-        for (final Step<?, ?> step : traversal.getSteps()) {
+
+        // we get accused of concurrentmodification if we try a for(Iterable)
+        final List<Step> steps = traversal.getSteps();
+        for (int ix = 0; ix < steps.size(); ix++) {
+            final Step step = steps.get(ix);
             if (step instanceof TraversalParent) {
                 for (final Traversal.Admin<?, ?> local : ((TraversalParent) step).getLocalChildren()) {
                     applyTraversalRecursively(consumer, local);
@@ -629,7 +633,7 @@
     }
 
     public static boolean onGraphComputer(Traversal.Admin<?, ?> traversal) {
-        while (!(traversal.getParent() instanceof EmptyStep)) {
+        while (!(traversal.isRoot())) {
             if (traversal.getParent() instanceof TraversalVertexProgramStep)
                 return true;
             traversal = traversal.getParent().asStep().getTraversal();
@@ -683,7 +687,7 @@
         childTraversal.setStrategies(parentTraversal.getStrategies());
         childTraversal.setSideEffects(parentTraversal.getSideEffects());
         parentTraversal.getGraph().ifPresent(childTraversal::setGraph);
-        for (final TraversalStrategy<?> strategy : parentTraversal.getStrategies().toList()) {
+        for (final TraversalStrategy<?> strategy : parentTraversal.getStrategies()) {
             strategy.apply(childTraversal);
             if (null != stopAfterStrategy && stopAfterStrategy.isInstance(strategy))
                 break;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalRing.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalRing.java
index 09c362e..bbdf701 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalRing.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalRing.java
@@ -24,6 +24,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
@@ -62,6 +63,15 @@
         this.traversals.add(traversal);
     }
 
+    public void replaceTraversal(final Traversal.Admin<A, B> oldTraversal, final Traversal.Admin<A, B> newTraversal) {
+        for (int i = 0, j = this.traversals.size(); i < j; i++) {
+            if (Objects.equals(oldTraversal, this.traversals.get(i))) {
+                this.traversals.set(i, newTraversal);
+                break;
+            }
+        }
+    }
+
     public List<Traversal.Admin<A, B>> getTraversals() {
         return Collections.unmodifiableList(this.traversals);
     }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Direction.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Direction.java
index d412e24..11db13d 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Direction.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Direction.java
@@ -23,7 +23,7 @@
  * {@link Edge}. For example:
  * <p/>
  * <pre>
- * gremlin--knows-->rexster
+ * gremlin--knows--&gt;rexster
  * </pre>
  * is an {@link Direction#OUT} {@link Edge} for Gremlin and an {@link Direction#IN} edge for Rexster. Moreover, given
  * that {@link Edge}, Gremlin is the {@link Direction#OUT} {@link Vertex} and Rexster is the {@link Direction#IN}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Edge.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Edge.java
index 6df38d2..fba9ae7 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Edge.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Edge.java
@@ -29,7 +29,7 @@
  * <p/>
  * Diagrammatically:
  * <pre>
- * outVertex ---label---> inVertex.
+ * outVertex ---label---&gt; inVertex.
  * </pre>
  *
  * @author Marko A. Rodriguez (http://markorodriguez.com)
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Graph.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Graph.java
index 5dd4ff5..da1c998 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Graph.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Graph.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.structure;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
@@ -271,13 +271,19 @@
     public Iterator<Edge> edges(final Object... edgeIds);
 
     /**
-     * Configure and control the transactions for those graphs that support this feature.  Note that this method does
-     * not indicate the creation of a "transaction" object.  A {@link Transaction} in the TinkerPop context is a
-     * transaction "factory" or "controller" that helps manage transactions owned by the underlying graph database.
+     * Configure and control the transactions for those graphs that support this feature.
      */
     public Transaction tx();
 
     /**
+     * Configure and control the transactions for those graphs that support this feature. Graphs that support multiple
+     * transaction models can use this method expose different sorts of {@link Transaction} implementations.
+     */
+    public default <Tx extends Transaction> Tx tx(final Class<Tx> txClass) {
+        throw new UnsupportedOperationException("This Graph does not support multiple transaction types - use tx() instead");
+    }
+
+    /**
      * Closing a {@code Graph} is equivalent to "shutdown" and implies that no further operations can be executed on
      * the instance.  Users should consult the documentation of the underlying graph database implementation for what
      * this "shutdown" will mean in general and, if supported, how open transactions are handled.  It will typically
@@ -323,8 +329,8 @@
     public Variables variables();
 
     /**
-     * Get the {@code Configuration} associated with the construction of this graph.  Whatever configuration was
-     * passed to {@link GraphFactory#open(Configuration)} is what should be returned by this method.
+     * Get the {@code Configuration} associated with the construction of this graph. Whatever configuration was passed
+     * to {@link GraphFactory#open(Configuration)} is what should be returned by this method.
      *
      * @return the configuration used during graph construction.
      */
@@ -686,6 +692,17 @@
             public static final String FEATURE_ANY_IDS = "AnyIds";
             public static final String FEATURE_ADD_PROPERTY = "AddProperty";
             public static final String FEATURE_REMOVE_PROPERTY = "RemoveProperty";
+            public static final String FEATURE_NULL_PROPERTY_VALUES = "NullPropertyValues";
+
+            /**
+             * Determines if an {@link Element} allows properties with {@code null} property values. In the event that
+             * this value is {@code false}, the underlying graph must treat {@code null} as an indication to remove
+             * the property.
+             */
+            @FeatureDescriptor(name = FEATURE_NULL_PROPERTY_VALUES)
+            public default boolean supportsNullPropertyValues() {
+                return true;
+            }
 
             /**
              * Determines if an {@link Element} allows properties to be added.  This feature is set independently from
@@ -820,6 +837,15 @@
             public static final String FEATURE_UUID_IDS = "UuidIds";
             public static final String FEATURE_CUSTOM_IDS = "CustomIds";
             public static final String FEATURE_ANY_IDS = "AnyIds";
+            public static final String FEATURE_NULL_PROPERTY_VALUES = "NullPropertyValues";
+
+            /**
+             * Determines if meta-properties allow for {@code null} property values.
+             */
+            @FeatureDescriptor(name = FEATURE_NULL_PROPERTY_VALUES)
+            public default boolean supportsNullPropertyValues() {
+                return true;
+            }
 
             /**
              * Determines if a {@link VertexProperty} allows properties to be removed.
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Property.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Property.java
index 5b67f07..eac8355 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Property.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Property.java
@@ -139,10 +139,6 @@
             return new IllegalArgumentException("Property key can not be null");
         }
 
-        public static IllegalArgumentException propertyValueCanNotBeNull() {
-            return new IllegalArgumentException("Property value can not be null");
-        }
-
         public static IllegalArgumentException propertyKeyCanNotBeAHiddenKey(final String key) {
             return new IllegalArgumentException("Property key can not be a hidden key: " + key);
         }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Transaction.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Transaction.java
index 64a58c8..d3a0eb6 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Transaction.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Transaction.java
@@ -18,27 +18,17 @@
  */
 package org.apache.tinkerpop.gremlin.structure;
 
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
 import org.apache.tinkerpop.gremlin.structure.util.AbstractTransaction;
 import org.apache.tinkerpop.gremlin.structure.util.TransactionException;
 
-import java.util.Collections;
-import java.util.Set;
-import java.util.function.BiFunction;
 import java.util.function.Consumer;
-import java.util.function.Function;
 
 /**
  * A set of methods that allow for control of transactional behavior of a {@link Graph} instance. Providers may
  * consider using {@link AbstractTransaction} as a base implementation that provides default features for most of
  * these methods.
- * <p/>
- * It is expected that this interface be implemented by providers in a {@link ThreadLocal} fashion. In other words
- * transactions are bound to the current thread, which means that any graph operation executed by the thread occurs
- * in the context of that transaction and that there may only be one thread executing in a single transaction.
- * <p/>
- * It is important to realize that this class is not a "transaction object".  It is a class that holds transaction
- * related methods thus hiding them from the {@link Graph} interface.  This object is not meant to be passed around
- * as a transactional context.
  *
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  * @author Stephen Mallette (http://stephen.genoprime.com)
@@ -72,7 +62,23 @@
      * threads to collaborate on the same transaction.  A standard transactional context tied to a {@link Graph}
      * that supports transactions will typically bind a transaction to a single thread via {@link ThreadLocal}.
      */
-    public <G extends Graph> G createThreadedTx();
+    public default <G extends Graph> G createThreadedTx() {
+        throw Transaction.Exceptions.threadedTransactionsNotSupported();
+    }
+
+    /**
+     * Starts a transaction in the context of a {@link GraphTraversalSource} instance. It is up to the
+     * {@link Transaction} implementation to decide what this means and up to users to be aware of that meaning.
+     */
+    public default <T extends TraversalSource> T begin() {
+        return (T) begin(GraphTraversalSource.class);
+    }
+
+    /**
+     * Starts a transaction in the context of a particular {@link TraversalSource} instance. It is up to the
+     * {@link Transaction} implementation to decide what this means and up to users to be aware of that meaning.
+     */
+    public <T extends TraversalSource> T begin(final Class<T> traversalSourceClass);
 
     /**
      * Determines if a transaction is currently open.
@@ -218,4 +224,66 @@
             }
         }
     }
+
+    public static final Transaction NO_OP = new Transaction() {
+        @Override
+        public void open() {
+            throw new UnsupportedOperationException("This Transaction implementation is a no-op for all methods");
+        }
+
+        @Override
+        public void commit() {
+            throw new UnsupportedOperationException("This Transaction implementation is a no-op for all methods");
+        }
+
+        @Override
+        public void rollback() {
+            throw new UnsupportedOperationException("This Transaction implementation is a no-op for all methods");
+        }
+
+        @Override
+        public <C extends TraversalSource> C begin(final Class<C> traversalSourceClass) {
+            throw new UnsupportedOperationException("This Transaction implementation is a no-op for all methods");
+        }
+
+        @Override
+        public boolean isOpen() {
+            throw new UnsupportedOperationException("This Transaction implementation is a no-op for all methods");
+        }
+
+        @Override
+        public void readWrite() {
+            throw new UnsupportedOperationException("This Transaction implementation is a no-op for all methods");
+        }
+
+        @Override
+        public void close() {
+            throw new UnsupportedOperationException("This Transaction implementation is a no-op for all methods");
+        }
+
+        @Override
+        public Transaction onReadWrite(final Consumer<Transaction> consumer) {
+            throw new UnsupportedOperationException("This Transaction implementation is a no-op for all methods");
+        }
+
+        @Override
+        public Transaction onClose(final Consumer<Transaction> consumer) {
+            throw new UnsupportedOperationException("This Transaction implementation is a no-op for all methods");
+        }
+
+        @Override
+        public void addTransactionListener(final Consumer<Status> listener) {
+            throw new UnsupportedOperationException("This Transaction implementation is a no-op for all methods");
+        }
+
+        @Override
+        public void removeTransactionListener(final Consumer<Status> listener) {
+            throw new UnsupportedOperationException("This Transaction implementation is a no-op for all methods");
+        }
+
+        @Override
+        public void clearTransactionListeners() {
+            throw new UnsupportedOperationException("This Transaction implementation is a no-op for all methods");
+        }
+    };
 }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Vertex.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Vertex.java
index 7b0d2a5..a972c72 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Vertex.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Vertex.java
@@ -29,7 +29,7 @@
  * <p/>
  * Diagrammatically:
  * <pre>
- * ---inEdges---> vertex ---outEdges--->.
+ * ---inEdges---&gt; vertex ---outEdges---&gt;.
  * </pre>
  *
  * @author Marko A. Rodriguez (http://markorodriguez.com)
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/GraphBinaryMapper.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/GraphBinaryMapper.java
new file mode 100644
index 0000000..049a90d
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/GraphBinaryMapper.java
@@ -0,0 +1,41 @@
+/*
+ * 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.structure.io.binary;
+
+/**
+ * Holds a {@link GraphBinaryReader} and {@link GraphBinaryWriter} which together allow mapping in and out of the
+ * GraphBinary format.
+ */
+public final class GraphBinaryMapper {
+    private final GraphBinaryWriter writer;
+    private final GraphBinaryReader reader;
+
+    public GraphBinaryMapper(final GraphBinaryWriter writer, final GraphBinaryReader reader) {
+        this.writer = writer;
+        this.reader = reader;
+    }
+
+    public GraphBinaryWriter getWriter() {
+        return writer;
+    }
+
+    public GraphBinaryReader getReader() {
+        return reader;
+    }
+}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/TypeSerializerRegistry.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/TypeSerializerRegistry.java
index 39aeaaf..ced0088 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/TypeSerializerRegistry.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/TypeSerializerRegistry.java
@@ -46,7 +46,9 @@
 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.io.IoRegistry;
 import org.apache.tinkerpop.gremlin.util.function.Lambda;
+import org.javatuples.Pair;
 
 import java.io.IOException;
 import java.lang.reflect.Modifier;
@@ -220,12 +222,27 @@
         /**
          * Provides a way to resolve the type serializer to use when there isn't any direct match.
          */
-        public Builder withFallbackResolver(Function<Class<?>, TypeSerializer<?>> fallbackResolver) {
+        public Builder withFallbackResolver(final Function<Class<?>, TypeSerializer<?>> fallbackResolver) {
             this.fallbackResolver = fallbackResolver;
             return this;
         }
 
         /**
+         * Add {@link CustomTypeSerializer} by way of an {@link IoRegistry}. The registry entries should be bound to
+         * {@link GraphBinaryIo}.
+         */
+        public Builder addRegistry(final IoRegistry registry) {
+            if (null == registry) throw new IllegalArgumentException("The registry cannot be null");
+
+            final List<Pair<Class, CustomTypeSerializer>> classSerializers = registry.find(GraphBinaryIo.class, CustomTypeSerializer.class);
+            for (Pair<Class,CustomTypeSerializer> cs : classSerializers) {
+                addCustomType(cs.getValue0(), cs.getValue1());
+            }
+
+            return this;
+        }
+
+        /**
          * Creates a new {@link TypeSerializerRegistry} instance based on the serializers added.
          */
         public TypeSerializerRegistry create() {
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/GraphSerializer.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/GraphSerializer.java
index d627f18..f107b8a 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/GraphSerializer.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/GraphSerializer.java
@@ -18,8 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.structure.io.binary.types;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.structure.io.binary.DataType;
 import org.apache.tinkerpop.gremlin.structure.io.binary.GraphBinaryReader;
 import org.apache.tinkerpop.gremlin.structure.io.binary.GraphBinaryWriter;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/SimpleTypeSerializer.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/SimpleTypeSerializer.java
index 36a0f93..8c7918f 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/SimpleTypeSerializer.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/SimpleTypeSerializer.java
@@ -62,7 +62,7 @@
     /**
      * Reads a non-nullable value according to the type format.
      * @param buffer A buffer which reader index has been set to the beginning of the {value}.
-     * @param context The binary writer.
+     * @param context The binary reader.
      * @return
      * @throws IOException
      */
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/SingleTypeSerializer.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/SingleTypeSerializer.java
index e8dfb5c..4abadda 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/SingleTypeSerializer.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/SingleTypeSerializer.java
@@ -28,7 +28,7 @@
 import java.util.function.Function;
 
 /**
- * Represents a serializer for types that be represented as a single value and that can be read and write
+ * Represents a serializer for types that can be represented as a single value and that can be read and write
  * in a single operation.
  */
 public class SingleTypeSerializer<T> extends SimpleTypeSerializer<T> {
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/TraversalStrategySerializer.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/TraversalStrategySerializer.java
index 38ea9c9..256e25d 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/TraversalStrategySerializer.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/TraversalStrategySerializer.java
@@ -18,8 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.structure.io.binary.types;
 
-import org.apache.commons.configuration.ConfigurationConverter;
-import org.apache.commons.configuration.MapConfiguration;
+import org.apache.commons.configuration2.ConfigurationConverter;
+import org.apache.commons.configuration2.MapConfiguration;
 import org.apache.tinkerpop.gremlin.structure.io.binary.DataType;
 import org.apache.tinkerpop.gremlin.structure.io.binary.GraphBinaryReader;
 import org.apache.tinkerpop.gremlin.structure.io.binary.GraphBinaryWriter;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLWriter.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLWriter.java
index 3991e4e..5c70e99 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLWriter.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLWriter.java
@@ -24,7 +24,6 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapper.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapper.java
index 30112f9..bfa239b 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapper.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapper.java
@@ -198,7 +198,7 @@
         private boolean loadCustomModules = false;
         private boolean normalize = false;
         private List<IoRegistry> registries = new ArrayList<>();
-        private GraphSONVersion version = GraphSONVersion.V2_0;
+        private GraphSONVersion version = GraphSONVersion.V3_0;
 
         /**
          * GraphSON 2.0/3.0 should have types activated by default (3.0 does not have a typeless option), and 1.0
@@ -219,7 +219,7 @@
         }
 
         /**
-         * Set the version of GraphSON to use. The default is {@link GraphSONVersion#V2_0}.
+         * Set the version of GraphSON to use. The default is {@link GraphSONVersion#V3_0}.
          */
         public Builder version(final GraphSONVersion version) {
             this.version = version;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java
index cb0eeaf..f51b34c 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java
@@ -41,9 +41,11 @@
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.HaltedTraverserStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.OptionsStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.PartitionStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SeedStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization.MatchAlgorithmStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.AdjacentToIncidentStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.ByModulatorOptimizationStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.EarlyLimitStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.FilterRankingStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.IdentityRemovalStrategy;
@@ -185,9 +187,12 @@
                             HaltedTraverserStrategy.class,
                             PartitionStrategy.class,
                             SubgraphStrategy.class,
+                            SeedStrategy.class,
                             LazyBarrierStrategy.class,
                             MatchAlgorithmStrategy.class,
                             AdjacentToIncidentStrategy.class,
+                            ByModulatorOptimizationStrategy.class,
+                            CountStrategy.class,
                             FilterRankingStrategy.class,
                             IdentityRemovalStrategy.class,
                             IncidentToAdjacentStrategy.class,
@@ -197,7 +202,6 @@
                             OptionsStrategy.class,
                             PathProcessorStrategy.class,
                             PathRetractionStrategy.class,
-                            CountStrategy.class,
                             RepeatUnrollStrategy.class,
                             ComputerVerificationStrategy.class,
                             LambdaRestrictionStrategy.class,
@@ -311,9 +315,12 @@
                     HaltedTraverserStrategy.class,
                     PartitionStrategy.class,
                     SubgraphStrategy.class,
+                    SeedStrategy.class,
                     LazyBarrierStrategy.class,
                     MatchAlgorithmStrategy.class,
                     AdjacentToIncidentStrategy.class,
+                    ByModulatorOptimizationStrategy.class,
+                    CountStrategy.class,
                     FilterRankingStrategy.class,
                     IdentityRemovalStrategy.class,
                     IncidentToAdjacentStrategy.class,
@@ -323,7 +330,6 @@
                     OptionsStrategy.class,
                     PathProcessorStrategy.class,
                     PathRetractionStrategy.class,
-                    CountStrategy.class,
                     RepeatUnrollStrategy.class,
                     ComputerVerificationStrategy.class,
                     LambdaRestrictionStrategy.class,
@@ -417,9 +423,12 @@
                             HaltedTraverserStrategy.class,
                             PartitionStrategy.class,
                             SubgraphStrategy.class,
+                            SeedStrategy.class,
                             LazyBarrierStrategy.class,
                             MatchAlgorithmStrategy.class,
                             AdjacentToIncidentStrategy.class,
+                            ByModulatorOptimizationStrategy.class,
+                            CountStrategy.class,
                             FilterRankingStrategy.class,
                             IdentityRemovalStrategy.class,
                             IncidentToAdjacentStrategy.class,
@@ -429,7 +438,6 @@
                             OptionsStrategy.class,
                             PathProcessorStrategy.class,
                             PathRetractionStrategy.class,
-                            CountStrategy.class,
                             RepeatUnrollStrategy.class,
                             ComputerVerificationStrategy.class,
                             LambdaRestrictionStrategy.class,
@@ -533,9 +541,12 @@
                     HaltedTraverserStrategy.class,
                     PartitionStrategy.class,
                     SubgraphStrategy.class,
+                    SeedStrategy.class,
                     LazyBarrierStrategy.class,
                     MatchAlgorithmStrategy.class,
                     AdjacentToIncidentStrategy.class,
+                    ByModulatorOptimizationStrategy.class,
+                    CountStrategy.class,
                     FilterRankingStrategy.class,
                     IdentityRemovalStrategy.class,
                     IncidentToAdjacentStrategy.class,
@@ -545,7 +556,6 @@
                     OptionsStrategy.class,
                     PathProcessorStrategy.class,
                     PathRetractionStrategy.class,
-                    CountStrategy.class,
                     RepeatUnrollStrategy.class,
                     ComputerVerificationStrategy.class,
                     LambdaRestrictionStrategy.class,
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/LegacyGraphSONReader.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/LegacyGraphSONReader.java
index 3125e73..7432e22 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/LegacyGraphSONReader.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/LegacyGraphSONReader.java
@@ -205,7 +205,6 @@
         private boolean loadCustomModules = false;
         private List<SimpleModule> customModules = new ArrayList<>();
         private long batchSize = 10000;
-        private boolean embedTypes = false;
 
         private Builder() {
         }
@@ -236,9 +235,12 @@
         }
 
         public LegacyGraphSONReader create() {
-            final GraphSONMapper.Builder builder = GraphSONMapper.build();
+            // not sure why there is specific need for V2 here with "no types" as we don't even need TP3 GraphSON
+            // at all. Seems like a standard Jackson ObjectMapper would have worked fine, but rather than change
+            // this ancient class at this stage we'll just stick to what is there.
+            final GraphSONMapper.Builder builder = GraphSONMapper.build().version(GraphSONVersion.V2_0);
             customModules.forEach(builder::addCustomModule);
-            final GraphSONMapper mapper = builder.typeInfo(embedTypes ? TypeInfo.PARTIAL_TYPES : TypeInfo.NO_TYPES)
+            final GraphSONMapper mapper = builder.typeInfo(TypeInfo.NO_TYPES)
                     .loadCustomModules(loadCustomModules).create();
             return new LegacyGraphSONReader(mapper.createMapper(), batchSize);
         }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/TraversalSerializersV2d0.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/TraversalSerializersV2d0.java
index 5297733..c66a1e8 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/TraversalSerializersV2d0.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/TraversalSerializersV2d0.java
@@ -19,8 +19,8 @@
 
 package org.apache.tinkerpop.gremlin.structure.io.graphson;
 
-import org.apache.commons.configuration.ConfigurationConverter;
-import org.apache.commons.configuration.MapConfiguration;
+import org.apache.commons.configuration2.ConfigurationConverter;
+import org.apache.commons.configuration2.MapConfiguration;
 import org.apache.tinkerpop.gremlin.process.remote.traversal.DefaultRemoteTraverser;
 import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
 import org.apache.tinkerpop.gremlin.process.traversal.P;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/TraversalSerializersV3d0.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/TraversalSerializersV3d0.java
index 8ace1e7..75782df 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/TraversalSerializersV3d0.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/TraversalSerializersV3d0.java
@@ -19,8 +19,8 @@
 
 package org.apache.tinkerpop.gremlin.structure.io.graphson;
 
-import org.apache.commons.configuration.ConfigurationConverter;
-import org.apache.commons.configuration.MapConfiguration;
+import org.apache.commons.configuration2.ConfigurationConverter;
+import org.apache.commons.configuration2.MapConfiguration;
 import org.apache.tinkerpop.gremlin.process.remote.traversal.DefaultRemoteTraverser;
 import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
 import org.apache.tinkerpop.gremlin.process.traversal.P;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java
index 3138488..eb9566e 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java
@@ -50,9 +50,11 @@
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.HaltedTraverserStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.OptionsStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.PartitionStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SeedStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization.MatchAlgorithmStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.AdjacentToIncidentStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.ByModulatorOptimizationStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.EarlyLimitStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.FilterRankingStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.IdentityRemovalStrategy;
@@ -333,10 +335,13 @@
             add(GryoTypeReg.of(HaltedTraverserStrategy.class, 139));
             add(GryoTypeReg.of(PartitionStrategy.class, 140, new JavaSerializer()));
             add(GryoTypeReg.of(SubgraphStrategy.class, 141, new JavaSerializer()));
+            add(GryoTypeReg.of(SeedStrategy.class, 192, new JavaSerializer()));          // ***LAST ID***
             add(GryoTypeReg.of(VertexProgramStrategy.class, 142, new JavaSerializer()));
             add(GryoTypeReg.of(MatchAlgorithmStrategy.class, 143));
             add(GryoTypeReg.of(MatchStep.GreedyMatchAlgorithm.class, 144));
             add(GryoTypeReg.of(AdjacentToIncidentStrategy.class, 145));
+            add(GryoTypeReg.of(ByModulatorOptimizationStrategy.class, 191));
+            add(GryoTypeReg.of(CountStrategy.class, 155));
             add(GryoTypeReg.of(FilterRankingStrategy.class, 146));
             add(GryoTypeReg.of(IdentityRemovalStrategy.class, 147));
             add(GryoTypeReg.of(IncidentToAdjacentStrategy.class, 148));
@@ -347,7 +352,6 @@
             add(GryoTypeReg.of(OptionsStrategy.class, 187, new JavaSerializer()));
             add(GryoTypeReg.of(PathProcessorStrategy.class, 153));
             add(GryoTypeReg.of(PathRetractionStrategy.class, 154));
-            add(GryoTypeReg.of(CountStrategy.class, 155));
             add(GryoTypeReg.of(RepeatUnrollStrategy.class, 156));
             add(GryoTypeReg.of(GraphFilterStrategy.class, 157));
             add(GryoTypeReg.of(LambdaRestrictionStrategy.class, 158));
@@ -356,7 +360,7 @@
             add(GryoTypeReg.of(MatchStep.CountMatchAlgorithm.class, 160));
             add(GryoTypeReg.of(MatchStep.GreedyMatchAlgorithm.class, 164));
             add(GryoTypeReg.of(EdgeLabelVerificationStrategy.class, 189));
-            add(GryoTypeReg.of(ReservedKeysVerificationStrategy.class, 190));   // ***LAST ID***
+            add(GryoTypeReg.of(ReservedKeysVerificationStrategy.class, 190));
 
             add(GryoTypeReg.of(TraverserSet.class, 58));
             add(GryoTypeReg.of(Tree.class, 61));
@@ -570,10 +574,13 @@
             add(GryoTypeReg.of(HaltedTraverserStrategy.class, 139));
             add(GryoTypeReg.of(PartitionStrategy.class, 140, new JavaSerializer()));
             add(GryoTypeReg.of(SubgraphStrategy.class, 141, new JavaSerializer()));
+            add(GryoTypeReg.of(SeedStrategy.class, 192, new JavaSerializer()));          // ***LAST ID***
             add(GryoTypeReg.of(VertexProgramStrategy.class, 142, new JavaSerializer()));
             add(GryoTypeReg.of(MatchAlgorithmStrategy.class, 143));
             add(GryoTypeReg.of(MatchStep.GreedyMatchAlgorithm.class, 144));
             add(GryoTypeReg.of(AdjacentToIncidentStrategy.class, 145));
+            add(GryoTypeReg.of(ByModulatorOptimizationStrategy.class, 191));
+            add(GryoTypeReg.of(CountStrategy.class, 155));
             add(GryoTypeReg.of(FilterRankingStrategy.class, 146));
             add(GryoTypeReg.of(IdentityRemovalStrategy.class, 147));
             add(GryoTypeReg.of(IncidentToAdjacentStrategy.class, 148));
@@ -584,7 +591,6 @@
             add(GryoTypeReg.of(OptionsStrategy.class, 187, new JavaSerializer()));
             add(GryoTypeReg.of(PathProcessorStrategy.class, 153));
             add(GryoTypeReg.of(PathRetractionStrategy.class, 154));
-            add(GryoTypeReg.of(CountStrategy.class, 155));
             add(GryoTypeReg.of(RepeatUnrollStrategy.class, 156));
             add(GryoTypeReg.of(GraphFilterStrategy.class, 157));
             add(GryoTypeReg.of(LambdaRestrictionStrategy.class, 158));
@@ -593,7 +599,7 @@
             add(GryoTypeReg.of(MatchStep.CountMatchAlgorithm.class, 160));
             add(GryoTypeReg.of(MatchStep.GreedyMatchAlgorithm.class, 167));
             add(GryoTypeReg.of(EdgeLabelVerificationStrategy.class, 189));
-            add(GryoTypeReg.of(ReservedKeysVerificationStrategy.class, 190));   // ***LAST ID***
+            add(GryoTypeReg.of(ReservedKeysVerificationStrategy.class, 190));
             // skip 171, 172 to sync with the 3.3.x
             add(GryoTypeReg.of(IndexedTraverserSet.VertexIndexedTraverserSet.class, 173));
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/kryoshim/KryoShimService.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/kryoshim/KryoShimService.java
index 4422e1b..6e7baff 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/kryoshim/KryoShimService.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/kryoshim/KryoShimService.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.structure.io.gryo.kryoshim;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 
 import java.io.InputStream;
 import java.io.OutputStream;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/kryoshim/KryoShimServiceLoader.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/kryoshim/KryoShimServiceLoader.java
index 97e6d16..3179905 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/kryoshim/KryoShimServiceLoader.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/kryoshim/KryoShimServiceLoader.java
@@ -18,9 +18,9 @@
  */
 package org.apache.tinkerpop.gremlin.structure.io.gryo.kryoshim;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.ConfigurationUtils;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.configuration2.ConfigurationUtils;
 import org.apache.tinkerpop.gremlin.util.SystemUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/util/IoRegistryHelper.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/util/IoRegistryHelper.java
index f878cfc..1db2197 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/util/IoRegistryHelper.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/util/IoRegistryHelper.java
@@ -19,7 +19,7 @@
 
 package org.apache.tinkerpop.gremlin.structure.io.util;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.structure.io.IoRegistry;
 
 import java.lang.reflect.Method;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/AbstractTransaction.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/AbstractTransaction.java
index bbc2bc6..ece32dc 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/AbstractTransaction.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/AbstractTransaction.java
@@ -18,11 +18,11 @@
  */
 package org.apache.tinkerpop.gremlin.structure.util;
 
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
 import org.apache.tinkerpop.gremlin.structure.Graph;
 import org.apache.tinkerpop.gremlin.structure.Transaction;
 
 import java.util.function.Consumer;
-import java.util.function.Function;
 
 /**
  * A simple base class for {@link Transaction} that provides some common functionality and default behavior.
@@ -34,10 +34,10 @@
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
 public abstract class AbstractTransaction implements Transaction {
-    private Graph g;
+    private Graph graph;
 
-    public AbstractTransaction(final Graph g) {
-        this.g = g;
+    public AbstractTransaction(final Graph graph) {
+        this.graph = graph;
     }
 
     /**
@@ -123,6 +123,11 @@
         throw Transaction.Exceptions.threadedTransactionsNotSupported();
     }
 
+    @Override
+    public <T extends TraversalSource> T begin(final Class<T> traversalSourceClass) {
+        return graph.traversal(traversalSourceClass);
+    }
+
     /**
      * {@inheritDoc}
      */
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/ElementHelper.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/ElementHelper.java
index 0ef7a63..6ba5b29 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/ElementHelper.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/ElementHelper.java
@@ -88,13 +88,11 @@
      * a pre-condition check prior to setting a property.
      *
      * @param key   the key of the property
-     * @param value the value of the property
+     * @param value the value of the property\
      * @throws IllegalArgumentException whether the key/value pair is legal and if not, a clear reason exception
      *                                  message is provided
      */
     public static void validateProperty(final String key, final Object value) throws IllegalArgumentException {
-        if (null == value)
-            throw Property.Exceptions.propertyValueCanNotBeNull();
         if (null == key)
             throw Property.Exceptions.propertyKeyCanNotBeNull();
         if (key.isEmpty())
@@ -105,7 +103,7 @@
 
     /**
      * Determines whether a list of key/values are legal, ensuring that there are an even number of values submitted
-     * and that the key values in the list of arguments are {@link String} or {@link Element} objects.
+     * and that the keys in the list of arguments are {@link String} or {@link T} objects.
      *
      * @param propertyKeyValues a list of key/value pairs
      * @throws IllegalArgumentException if something in the pairs is illegal
@@ -116,10 +114,6 @@
         for (int i = 0; i < propertyKeyValues.length; i = i + 2) {
             if (!(propertyKeyValues[i] instanceof String) && !(propertyKeyValues[i] instanceof T))
                 throw Element.Exceptions.providedKeyValuesMustHaveALegalKeyOnEvenIndices();
-
-            if (null == propertyKeyValues[i + 1]) {
-                throw Property.Exceptions.propertyValueCanNotBeNull();
-            }
         }
     }
 
@@ -128,12 +122,11 @@
      *
      * @param keyValues a list of key/value pairs
      * @return the value associated with {@link T#id}
-     * @throws NullPointerException if the value for the {@link T#id} key is {@code null}
      */
     public static Optional<Object> getIdValue(final Object... keyValues) {
         for (int i = 0; i < keyValues.length; i = i + 2) {
             if (keyValues[i].equals(T.id))
-                return Optional.of(keyValues[i + 1]);
+                return Optional.ofNullable(keyValues[i + 1]);
         }
         return Optional.empty();
     }
@@ -280,16 +273,24 @@
         if (null == element)
             throw Graph.Exceptions.argumentCanNotBeNull("element");
 
+        final boolean allowNullPropertyValues = element instanceof Vertex ?
+                element.graph().features().vertex().supportsNullPropertyValues() : element instanceof Edge ?
+                element.graph().features().edge().supportsNullPropertyValues() :
+                element.graph().features().vertex().properties().supportsNullPropertyValues();
+
         for (int i = 0; i < propertyKeyValues.length; i = i + 2) {
             if (!propertyKeyValues[i].equals(T.id) && !propertyKeyValues[i].equals(T.label))
-                element.property((String) propertyKeyValues[i], propertyKeyValues[i + 1]);
+                if (!allowNullPropertyValues && null == propertyKeyValues[i + 1])
+                    element.properties(((String) propertyKeyValues[i])).forEachRemaining(Property::remove);
+                else
+                    element.property((String) propertyKeyValues[i], propertyKeyValues[i + 1]);
         }
     }
 
     /**
-     * Assign key/value pairs as properties to an {@link Vertex}.  If the value of {@link T#id} or
-     * {@link T#label} is in the set of pairs, then they are ignored.
-     * The {@link VertexProperty.Cardinality} of the key is determined from the {@link Graph.Features.VertexFeatures}.
+     * Assign key/value pairs as properties to an {@link Vertex}.  If the value of {@link T#id} or {@link T#label} is
+     * in the set of pairs, then they are ignored. The {@link VertexProperty.Cardinality} of the key is determined from
+     * the {@link Graph.Features.VertexFeatures}.
      *
      * @param vertex            the graph vertex to assign the {@code propertyKeyValues}
      * @param propertyKeyValues the key/value pairs to assign to the {@code element}
@@ -300,15 +301,20 @@
         if (null == vertex)
             throw Graph.Exceptions.argumentCanNotBeNull("vertex");
 
+        final boolean allowNullPropertyValues = vertex.graph().features().vertex().supportsNullPropertyValues();
+
         for (int i = 0; i < propertyKeyValues.length; i = i + 2) {
             if (!propertyKeyValues[i].equals(T.id) && !propertyKeyValues[i].equals(T.label))
-                vertex.property(vertex.graph().features().vertex().getCardinality((String) propertyKeyValues[i]), (String) propertyKeyValues[i], propertyKeyValues[i + 1]);
+                if (!allowNullPropertyValues && null == propertyKeyValues[i + 1])
+                    vertex.properties(((String) propertyKeyValues[i])).forEachRemaining(VertexProperty::remove);
+                else
+                    vertex.property(vertex.graph().features().vertex().getCardinality((String) propertyKeyValues[i]), (String) propertyKeyValues[i], propertyKeyValues[i + 1]);
         }
     }
 
     /**
-     * Assign key/value pairs as properties to a {@link Vertex}.
-     * If the value of {@link T#id} or {@link T#label} is in the set of pairs, then they are ignored.
+     * Assign key/value pairs as properties to a {@link Vertex}. If the value of {@link T#id} or {@link T#label} is
+     * in the set of pairs, then they are ignored.
      *
      * @param vertex            the vertex to attach the properties to
      * @param cardinality       the cardinality of the key value pair settings
@@ -316,18 +322,24 @@
      * @throws ClassCastException       if the value of the key is not a {@link String}
      * @throws IllegalArgumentException if the value of {@code element} is null
      */
-    public static void attachProperties(final Vertex vertex, final VertexProperty.Cardinality cardinality, final Object... propertyKeyValues) {
+    public static void attachProperties(final Vertex vertex, final VertexProperty.Cardinality cardinality,
+                                        final Object... propertyKeyValues) {
         if (null == vertex)
             throw Graph.Exceptions.argumentCanNotBeNull("vertex");
 
+        final boolean allowNullPropertyValues = vertex.graph().features().vertex().supportsNullPropertyValues();
+
         for (int i = 0; i < propertyKeyValues.length; i = i + 2) {
             if (!propertyKeyValues[i].equals(T.id) && !propertyKeyValues[i].equals(T.label))
-                vertex.property(cardinality, (String) propertyKeyValues[i], propertyKeyValues[i + 1]);
+                if (!allowNullPropertyValues && null == propertyKeyValues[i + 1])
+                    vertex.properties(((String) propertyKeyValues[i])).forEachRemaining(VertexProperty::remove);
+                else
+                    vertex.property(cardinality, (String) propertyKeyValues[i], propertyKeyValues[i + 1]);
         }
     }
 
     /**
-     * This is a helper method for dealing with vertex property cardinality and typically used in {@link Vertex#property(org.apache.tinkerpop.gremlin.structure.VertexProperty.Cardinality, String, Object, Object...)}.
+     * This is a helper method for dealing with vertex property cardinality and typically used in {@link Vertex#property(VertexProperty.Cardinality, String, Object, Object...)}.
      * If the cardinality is list, simply return {@link Optional#empty}.
      * If the cardinality is single, delete all existing properties of the provided key and return {@link Optional#empty}.
      * If the cardinality is set, find one that has the same key/value and attached the properties to it and return it. Else, if no equal value is found, return {@link Optional#empty}.
@@ -340,7 +352,9 @@
      * @param <V>         the type of the vertex property value
      * @return a vertex property if it has been found in set with equal value
      */
-    public static <V> Optional<VertexProperty<V>> stageVertexProperty(final Vertex vertex, final VertexProperty.Cardinality cardinality, final String key, final V value, final Object... keyValues) {
+    public static <V> Optional<VertexProperty<V>> stageVertexProperty(final Vertex vertex,
+                                                                      final VertexProperty.Cardinality cardinality,
+                                                                      final String key, final V value, final Object... keyValues) {
         if (cardinality.equals(VertexProperty.Cardinality.single))
             vertex.properties(key).forEachRemaining(VertexProperty::remove);
         else if (cardinality.equals(VertexProperty.Cardinality.set)) {
@@ -387,7 +401,8 @@
 
     /**
      * A standard method for determining if two {@link Element} objects are equal. This method should be used by any
-     * {@link Object#equals(Object)} implementation to ensure consistent behavior. This method is used for Vertex, Edge, and VertexProperty.
+     * {@link Object#equals(Object)} implementation to ensure consistent behavior. This method is used for Vertex,
+     * Edge, and VertexProperty.
      *
      * @param a The first {@link Element}
      * @param b The second {@link Element} (as an {@link Object})
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/GraphFactory.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/GraphFactory.java
index 61808aa..b670034 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/GraphFactory.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/GraphFactory.java
@@ -18,13 +18,16 @@
  */
 package org.apache.tinkerpop.gremlin.structure.util;
 
+import org.apache.commons.configuration2.ConfigurationUtils;
+import org.apache.commons.configuration2.FileBasedConfiguration;
+import org.apache.commons.configuration2.YAMLConfiguration;
+import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder;
+import org.apache.commons.configuration2.builder.fluent.Configurations;
+import org.apache.commons.configuration2.builder.fluent.Parameters;
 import org.apache.tinkerpop.gremlin.structure.Graph;
-import org.apache.tinkerpop.gremlin.util.config.YamlConfiguration;
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.ConfigurationException;
-import org.apache.commons.configuration.MapConfiguration;
-import org.apache.commons.configuration.PropertiesConfiguration;
-import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.configuration2.ex.ConfigurationException;
+import org.apache.commons.configuration2.MapConfiguration;
 
 import java.io.File;
 import java.util.Map;
@@ -106,8 +109,9 @@
     /**
      * Open a graph. See each {@link Graph} instance for its configuration options.
      *
-     * @param configuration A {@code Map} based configuration that will be converted to an {@code Configuration} object
-     *                      via {@code MapConfiguration} and passed to the appropriate overload.
+     * @param configuration A {@code Map} based configuration that will be converted to an
+     *                      {@code Configuration} object via {@code MapConfiguration} and passed to the appropriate
+     *                      overload.
      * @return A Graph instance.
      */
     public static Graph open(final Map configuration) {
@@ -115,7 +119,7 @@
         return open(new MapConfiguration(configuration));
     }
 
-    private static Configuration getConfiguration(final File configurationFile) {
+    private static org.apache.commons.configuration2.Configuration getConfiguration(final File configurationFile) {
         if (!configurationFile.isFile())
             throw new IllegalArgumentException(String.format("The location configuration must resolve to a file and [%s] does not", configurationFile));
 
@@ -123,18 +127,29 @@
             final String fileName = configurationFile.getName();
             final String fileExtension = fileName.substring(fileName.lastIndexOf('.') + 1);
 
+            final Configuration conf;
+            final Configurations configs = new Configurations();
+
             switch (fileExtension) {
                 case "yml":
                 case "yaml":
-                    final YamlConfiguration config = new YamlConfiguration();
-                    config.load(configurationFile);
-                    return config;
+                    final Parameters params = new Parameters();
+                    final FileBasedConfigurationBuilder<FileBasedConfiguration> builder =
+                            new FileBasedConfigurationBuilder<FileBasedConfiguration>(YAMLConfiguration.class).
+                                    configure(params.fileBased().setFile(configurationFile));
+
+                    final org.apache.commons.configuration2.Configuration copy = new org.apache.commons.configuration2.BaseConfiguration();
+                    ConfigurationUtils.copy(builder.configure(params.fileBased().setFile(configurationFile)).getConfiguration(), copy);
+                    conf = copy;
+                    break;
                 case "xml":
-                    return new XMLConfiguration(configurationFile);
+                    conf = configs.xml(configurationFile);
+                    break;
                 default:
-                    return new PropertiesConfiguration(configurationFile);
+                    conf = configs.properties(configurationFile);
             }
-        } catch (final ConfigurationException e) {
+            return conf;
+        } catch (ConfigurationException e) {
             throw new IllegalArgumentException(String.format("Could not load configuration at: %s", configurationFile), e);
         }
     }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/StringFactory.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/StringFactory.java
index ede2baf..dfab163 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/StringFactory.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/StringFactory.java
@@ -52,6 +52,7 @@
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Optional;
 import java.util.function.Function;
 import java.util.function.Predicate;
@@ -269,6 +270,6 @@
     }
 
     public static String pathString(final Path path) {
-        return PATH + L_BRACKET + String.join(", ", IteratorUtils.map(path, Object::toString)) + R_BRACKET;
+        return PATH + L_BRACKET + String.join(", ", IteratorUtils.map(path, Objects::toString)) + R_BRACKET;
     }
 }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/TemporaryException.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/TemporaryException.java
new file mode 100644
index 0000000..99f06f2
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/TemporaryException.java
@@ -0,0 +1,27 @@
+/*
+ * 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.structure.util;
+
+/**
+ * Any exception that implements this interface will be recognized as one whose throwing operation is correct but can
+ * be retried. In other words, the state of the system may be such that a failure, like a database locking error,
+ * could be resolved for the same request at a future time.
+ */
+public interface TemporaryException {
+}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/empty/EmptyGraph.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/empty/EmptyGraph.java
index fa10c99..7d4e836 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/empty/EmptyGraph.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/empty/EmptyGraph.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.structure.util.empty;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
 import org.apache.tinkerpop.gremlin.structure.Edge;
 import org.apache.tinkerpop.gremlin.structure.Graph;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/star/StarGraph.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/star/StarGraph.java
index aa87d11..3bcdb7d 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/star/StarGraph.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/star/StarGraph.java
@@ -18,8 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.structure.util.star;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
 import org.apache.tinkerpop.gremlin.process.computer.GraphFilter;
 import org.apache.tinkerpop.gremlin.structure.Direction;
@@ -224,14 +224,6 @@
         return starGraph;
     }
 
-    /**
-     * @deprecated As of release 3.3.5, replaced by {@link #build()}.
-     */
-    @Deprecated
-    public static StarGraph.Builder builder() {
-        return build();
-    }
-
     public static StarGraph.Builder build() {
         return new Builder();
     }
@@ -244,7 +236,7 @@
         private boolean compareIdsUsingStrings = true;
 
         /**
-         * Call {@link #builder()} to instantiate
+         * Call {@link #build()} to instantiate
          */
         private Builder() { }
 
@@ -270,9 +262,6 @@
          * However, if this builder method is never invoked, then the builder is guaranteed to use
          * whatever default value StarGraph's other public constructors or factory methods would use.
          * This option exists solely for performance tuning in specialized use-cases.
-         *
-         * @param b
-         * @return
          */
         public Builder compareIdsUsingStrings(final boolean b) {
             this.compareIdsUsingStrings = b;
@@ -281,15 +270,6 @@
 
         /**
          * @return a new StarGraph
-         * @deprecated As of release 3.3.5, replaced by {@link #create()}.
-         */
-        @Deprecated
-        public StarGraph build() {
-            return create();
-        }
-
-        /**
-         * @return a new StarGraph
          */
         public StarGraph create() {
             return new StarGraph(internStrings, compareIdsUsingStrings);
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/SystemUtil.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/SystemUtil.java
index bc2c5ff..be6c813 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/SystemUtil.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/SystemUtil.java
@@ -19,8 +19,8 @@
 
 package org.apache.tinkerpop.gremlin.util;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
 
 import java.util.Map;
 
@@ -43,7 +43,6 @@
      */
     public static Configuration getSystemPropertiesConfiguration(final String prefix, final boolean trimPrefix) {
         final BaseConfiguration apacheConfiguration = new BaseConfiguration();
-        apacheConfiguration.setDelimiterParsingDisabled(true);
         for (final Map.Entry<Object, Object> entry : System.getProperties().entrySet()) {
             final String key = entry.getKey().toString();
             final Object value = entry.getValue();
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/TestSupport.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/TestSupport.java
index ee10491..f6e29b3 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/TestSupport.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/TestSupport.java
@@ -19,8 +19,6 @@
 package org.apache.tinkerpop.gremlin.util;
 
 import org.apache.tinkerpop.gremlin.structure.io.Storage;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.io.File;
 import java.io.FileOutputStream;
@@ -29,7 +27,6 @@
 import java.net.URL;
 import java.nio.file.Files;
 import java.util.List;
-import java.util.Random;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -173,7 +170,7 @@
         final File tempFile = new File(temp, resourceName + extension);
 
         // these checks are present mostly for windows compatibility where an outputstream created on a non-existent
-        // file will cause an error. 
+        // file will cause an error.
         if(tempFile.exists() && !overwrite){
             // overwrite is disabled and file already exists -> reuse as-is
             return tempFile;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/config/YamlConfiguration.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/config/YamlConfiguration.java
deleted file mode 100644
index 1ccdb41..0000000
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/config/YamlConfiguration.java
+++ /dev/null
@@ -1,127 +0,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.
- */
-package org.apache.tinkerpop.gremlin.util.config;
-
-import org.apache.commons.configuration.AbstractHierarchicalFileConfiguration;
-import org.apache.commons.configuration.ConfigurationException;
-import org.apache.commons.configuration.tree.ConfigurationNode;
-import org.yaml.snakeyaml.DumperOptions;
-import org.yaml.snakeyaml.Yaml;
-
-import java.io.Reader;
-import java.io.Writer;
-import java.util.Collection;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-/**
- * Apache Commons Configuration object for YAML.  Adapted from code originally found here:
- * https://github.com/PEXPlugins/SimpleConfigs
- *
- * @author Stephen Mallette (http://stephen.genoprime.com)
- */
-public class YamlConfiguration extends AbstractHierarchicalFileConfiguration {
-    public final static int DEFAULT_IDENT = 4;
-    private final DumperOptions yamlOptions = new DumperOptions();
-    private final Yaml yaml = new Yaml(yamlOptions);
-    private boolean xmlCompatibility = true;
-
-    public YamlConfiguration() {
-        super();
-        initialize();
-    }
-
-    private void initialize() {
-        yamlOptions.setIndent(DEFAULT_IDENT);
-        yamlOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
-    }
-
-    public void setXmlCompatibility(final boolean xmlCompatibility) {
-        this.xmlCompatibility = xmlCompatibility;
-    }
-
-    @Override
-    public void load(final Reader in) throws ConfigurationException {
-        try {
-            this.loadHierarchy(this.getRootNode(), yaml.load(in));
-        } catch (Throwable e) {
-            throw new ConfigurationException("Failed to load configuration: " + e.getMessage(), e);
-        }
-    }
-
-    @Override
-    public void save(final Writer out) throws ConfigurationException {
-        try {
-            yaml.dump(this.saveHierarchy(this.getRootNode()), out);
-        } catch (Throwable e) {
-            throw new ConfigurationException("Failed to save configuration: " + e.getMessage(), e);
-        }
-    }
-
-    protected void loadHierarchy(final ConfigurationNode parentNode, final Object obj) {
-        final String parentName = parentNode.getName();
-        if (obj instanceof Map<?, ?>) {
-            for (Map.Entry<String, Object> entry : ((Map<String, Object>) obj).entrySet()) {
-                final Node childNode = new Node(entry.getKey());
-
-                // if parent node is look like "tableS", "userS" or "groupS"
-                if (this.xmlCompatibility && parentName != null && parentName.endsWith("s")) {
-                    //this is done to have "users.user[@name='smith'] instead of "users.smith"
-                    childNode.setName(parentName.substring(0, parentName.length() - 1));
-                    childNode.addAttribute(new Node("name", entry.getKey()));
-                }
-
-                childNode.setReference(entry);
-                loadHierarchy(childNode, entry.getValue());
-                parentNode.addChild(childNode);
-            }
-        } else if (obj instanceof Collection) {
-            for (Object child : (Collection) obj) {
-                final Node childNode = new Node("item");
-                childNode.setReference(child);
-                loadHierarchy(childNode, child);
-                parentNode.addChild(childNode);
-            }
-        }
-
-        parentNode.setValue(obj);
-    }
-
-    protected Object saveHierarchy(final ConfigurationNode parentNode) {
-        if (parentNode.getChildrenCount() == 0)
-            return parentNode.getValue();
-
-        if (parentNode.getChildrenCount("item") == parentNode.getChildrenCount()) {
-            return parentNode.getChildren().stream().map(this::saveHierarchy).collect(Collectors.toList());
-        } else {
-            final Map<String, Object> map = new LinkedHashMap<>();
-            for (ConfigurationNode childNode : parentNode.getChildren()) {
-                String nodeName = childNode.getName();
-                if (this.xmlCompatibility && childNode.getAttributes("name").size() > 0)
-                    nodeName = String.valueOf(childNode.getAttributes("name").get(0).getValue());
-
-
-                map.put(nodeName, saveHierarchy(childNode));
-            }
-
-            return map;
-        }
-    }
-}
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/TraversalStrategiesTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/TraversalStrategiesTest.java
index 1b90435..1247986 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/TraversalStrategiesTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/TraversalStrategiesTest.java
@@ -18,8 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.process;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.process.computer.ComputerResult;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
 import org.apache.tinkerpop.gremlin.process.computer.MapReduce;
@@ -66,10 +66,11 @@
         TestGraph graph = new TestGraph();
         TraversalStrategies strategies = graph.traversal().getStrategies();
         assertFalse(TraversalStrategies.GlobalCache.getStrategies(Graph.class).toList().isEmpty());
-        for (final TraversalStrategy strategy : TraversalStrategies.GlobalCache.getStrategies(Graph.class).toList()) {
+        assertTrue(TraversalStrategies.GlobalCache.getStrategies(Graph.class).iterator().hasNext());
+        for (final TraversalStrategy strategy : TraversalStrategies.GlobalCache.getStrategies(Graph.class)) {
             assertTrue(strategies.getStrategy(strategy.getClass()).isPresent());
         }
-        for (final TraversalStrategy strategy : TraversalStrategies.GlobalCache.getStrategies(TestGraphComputer.class).toList()) {
+        for (final TraversalStrategy strategy : TraversalStrategies.GlobalCache.getStrategies(TestGraphComputer.class)) {
             assertFalse(strategies.getStrategy(strategy.getClass()).isPresent());
         }
         assertTrue(strategies.getStrategy(StrategyA.class).isPresent());
@@ -83,10 +84,10 @@
         ///
         graph = new TestGraph();
         strategies = graph.traversal().getStrategies();
-        for (final TraversalStrategy strategy : TraversalStrategies.GlobalCache.getStrategies(Graph.class).toList()) {
+        for (final TraversalStrategy strategy : TraversalStrategies.GlobalCache.getStrategies(Graph.class)) {
             assertTrue(strategies.getStrategy(strategy.getClass()).isPresent());
         }
-        for (final TraversalStrategy strategy : TraversalStrategies.GlobalCache.getStrategies(TestGraphComputer.class).toList()) {
+        for (final TraversalStrategy strategy : TraversalStrategies.GlobalCache.getStrategies(TestGraphComputer.class)) {
             assertFalse(strategies.getStrategy(strategy.getClass()).isPresent());
         }
         assertFalse(strategies.getStrategy(StrategyA.class).isPresent());
@@ -98,10 +99,10 @@
         //////////////////////
         strategies = TraversalStrategies.GlobalCache.getStrategies(TestGraphComputer.class);
         assertFalse(TraversalStrategies.GlobalCache.getStrategies(GraphComputer.class).toList().isEmpty());
-        for (final TraversalStrategy strategy : TraversalStrategies.GlobalCache.getStrategies(GraphComputer.class).toList()) {
+        for (final TraversalStrategy strategy : TraversalStrategies.GlobalCache.getStrategies(GraphComputer.class)) {
             assertTrue(strategies.getStrategy(strategy.getClass()).isPresent());
         }
-        for (final TraversalStrategy strategy : TraversalStrategies.GlobalCache.getStrategies(TestGraph.class).toList()) {
+        for (final TraversalStrategy strategy : TraversalStrategies.GlobalCache.getStrategies(TestGraph.class)) {
             assertFalse(strategies.getStrategy(strategy.getClass()).isPresent());
         }
         assertFalse(strategies.getStrategy(StrategyA.class).isPresent());
@@ -112,10 +113,10 @@
         //
         strategies = TraversalStrategies.GlobalCache.getStrategies(TestGraphComputer.class);
         assertFalse(TraversalStrategies.GlobalCache.getStrategies(GraphComputer.class).toList().isEmpty());
-        for (final TraversalStrategy strategy : TraversalStrategies.GlobalCache.getStrategies(GraphComputer.class).toList()) {
+        for (final TraversalStrategy strategy : TraversalStrategies.GlobalCache.getStrategies(GraphComputer.class)) {
             assertTrue(strategies.getStrategy(strategy.getClass()).isPresent());
         }
-        for (final TraversalStrategy strategy : TraversalStrategies.GlobalCache.getStrategies(TestGraph.class).toList()) {
+        for (final TraversalStrategy strategy : TraversalStrategies.GlobalCache.getStrategies(TestGraph.class)) {
             assertFalse(strategies.getStrategy(strategy.getClass()).isPresent());
         }
         assertFalse(strategies.getStrategy(StrategyA.class).isPresent());
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/verifcation/VertexProgramRestrictionStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/verifcation/VertexProgramRestrictionStrategyTest.java
new file mode 100644
index 0000000..b8a31d1
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/verifcation/VertexProgramRestrictionStrategyTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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.computer.traversal.strategy.verifcation;
+
+import org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.verification.VertexProgramRestrictionStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+
+import static org.junit.Assert.fail;
+
+/**
+ * @author Marc de Lignie
+ */
+@RunWith(Parameterized.class)
+public class VertexProgramRestrictionStrategyTest {
+
+    @Parameterized.Parameters(name = "{0}")
+    public static Iterable<Object[]> data() {
+        return Arrays.asList(new Object[][]{
+                // illegal
+                {"withComputer().withStrategies(VertexProgramRestrictionStrategy.instance()).V()",
+                        EmptyGraph.instance().traversal().withComputer().withStrategies(VertexProgramRestrictionStrategy.instance()).V(), false},
+                {"withStrategies(VertexProgramRestrictionStrategy.instance()).withComputer().V()",
+                        EmptyGraph.instance().traversal().withStrategies(VertexProgramRestrictionStrategy.instance()).withComputer().V(), false},
+                {"withStrategies(VertexProgramRestrictionStrategy.instance()).withComputer().V().connectedComponent()",
+                        EmptyGraph.instance().traversal().withStrategies(VertexProgramRestrictionStrategy.instance()).withComputer().V().connectedComponent(), false},
+                {"withStrategies(VertexProgramRestrictionStrategy.instance()).withComputer().V().pageRank()",
+                        EmptyGraph.instance().traversal().withStrategies(VertexProgramRestrictionStrategy.instance()).withComputer().V().pageRank(), false},
+                // legal
+                {"withStrategies(VertexProgramRestrictionStrategy.instance()).V()", EmptyGraph.instance().traversal().withStrategies(VertexProgramRestrictionStrategy.instance()).V(), true},
+        });
+    }
+
+    @Parameterized.Parameter(value = 0)
+    public String name;
+
+    @Parameterized.Parameter(value = 1)
+    public Traversal<?, ?> traversal;
+
+    @Parameterized.Parameter(value = 2)
+    public boolean legal;
+
+    @Test
+    public void shouldBeVerifiedIllegal() {
+        try {
+            this.traversal.asAdmin().applyStrategies();
+            if (!this.legal)
+                fail("The traversal should not be allowed: " + this.traversal);
+        } catch (final IllegalStateException ise) {
+            if (this.legal)
+                fail("The traversal should be allowed: " + this.traversal);
+        }
+    }
+}
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/OrderTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/OrderTest.java
index b2d3084..0204399 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/OrderTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/OrderTest.java
@@ -44,13 +44,17 @@
     @Parameterized.Parameters(name = "{0}.test({1},{2})")
     public static Iterable<Object[]> data() throws ParseException {
         return new ArrayList<>(Arrays.asList(new Object[][]{
+                {Order.asc, Arrays.asList("a", "c", null, "d"), Arrays.asList(null, "a", "c", "d")},
                 {Order.asc, Arrays.asList("b", "a", "c", "d"), Arrays.asList("a", "b", "c", "d")},
                 {Order.desc, Arrays.asList("b", "a", "c", "d"), Arrays.asList("d", "c", "b", "a")},
+                {Order.desc, Arrays.asList("c", "a", null, "d"), Arrays.asList("d", "c", "a", null)},
                 {Order.asc, Arrays.asList(formatter.parse("1-Jan-2018"), formatter.parse("1-Jan-2020"), formatter.parse("1-Jan-2008")),
                             Arrays.asList(formatter.parse("1-Jan-2008"), formatter.parse("1-Jan-2018"), formatter.parse("1-Jan-2020"))},
                 {Order.desc, Arrays.asList(formatter.parse("1-Jan-2018"), formatter.parse("1-Jan-2020"), formatter.parse("1-Jan-2008")),
                              Arrays.asList(formatter.parse("1-Jan-2020"), formatter.parse("1-Jan-2018"), formatter.parse("1-Jan-2008"))},
+                {Order.desc, Arrays.asList(100L, 1L, null, -1L, 0L), Arrays.asList(100L, 1L, 0L, -1L, null)},
                 {Order.desc, Arrays.asList(100L, 1L, -1L, 0L), Arrays.asList(100L, 1L, 0L, -1L)},
+                {Order.asc, Arrays.asList(100L, 1L, null, -1L, 0L), Arrays.asList(null, -1L, 0L, 1L, 100L)},
                 {Order.asc, Arrays.asList(100.1f, 1.1f, -1.1f, 0.1f), Arrays.asList(-1.1f, 0.1f, 1.1f, 100.1f)},
                 {Order.desc, Arrays.asList(100.1f, 1.1f, -1.1f, 0.1f), Arrays.asList(100.1f, 1.1f, 0.1f, -1.1f)},
                 {Order.asc, Arrays.asList(100.1d, 1.1d, -1.1d, 0.1d), Arrays.asList(-1.1d, 0.1d, 1.1d, 100.1d)},
@@ -60,22 +64,7 @@
                 {Order.asc, Arrays.asList(100, 1, -1, 0), Arrays.asList(-1, 0, 1, 100)},
                 {Order.desc, Arrays.asList(100, 1, -1, 0), Arrays.asList(100, 1, 0, -1)},
                 {Order.asc, Arrays.asList("b", "a", T.id, "c", "d"), Arrays.asList("a", "b", "c", "d", T.id)},
-                {Order.desc, Arrays.asList("b", "a", T.id, "c", "d"), Arrays.asList(T.id, "d", "c", "b", "a")},
-                {Order.incr, Arrays.asList("b", "a", "c", "d"), Arrays.asList("a", "b", "c", "d")},
-                {Order.decr, Arrays.asList("b", "a", "c", "d"), Arrays.asList("d", "c", "b", "a")},
-                {Order.incr, Arrays.asList(formatter.parse("1-Jan-2018"), formatter.parse("1-Jan-2020"), formatter.parse("1-Jan-2008")),
-                             Arrays.asList(formatter.parse("1-Jan-2008"), formatter.parse("1-Jan-2018"), formatter.parse("1-Jan-2020"))},
-                {Order.decr, Arrays.asList(formatter.parse("1-Jan-2018"), formatter.parse("1-Jan-2020"), formatter.parse("1-Jan-2008")),
-                             Arrays.asList(formatter.parse("1-Jan-2020"), formatter.parse("1-Jan-2018"), formatter.parse("1-Jan-2008"))},
-                {Order.decr, Arrays.asList(100L, 1L, -1L, 0L), Arrays.asList(100L, 1L, 0L, -1L)},
-                {Order.incr, Arrays.asList(100.1f, 1.1f, -1.1f, 0.1f), Arrays.asList(-1.1f, 0.1f, 1.1f, 100.1f)},
-                {Order.decr, Arrays.asList(100.1f, 1.1f, -1.1f, 0.1f), Arrays.asList(100.1f, 1.1f, 0.1f, -1.1f)},
-                {Order.incr, Arrays.asList(100.1d, 1.1d, -1.1d, 0.1d), Arrays.asList(-1.1d, 0.1d, 1.1d, 100.1d)},
-                {Order.decr, Arrays.asList(100.1d, 1.1d, -1.1d, 0.1d), Arrays.asList(100.1d, 1.1d, 0.1d, -1.1d)},
-                {Order.incr, Arrays.asList(100L, 1L, -1L, 0L), Arrays.asList(-1L, 0L, 1L, 100L)},
-                {Order.decr, Arrays.asList(100L, 1L, -1L, 0L), Arrays.asList(100L, 1L, 0L, -1L)},
-                {Order.incr, Arrays.asList(100, 1, -1, 0), Arrays.asList(-1, 0, 1, 100)},
-                {Order.decr, Arrays.asList(100, 1, -1, 0), Arrays.asList(100, 1, 0, -1)}}));
+                {Order.desc, Arrays.asList("b", "a", T.id, "c", "d"), Arrays.asList(T.id, "d", "c", "b", "a")}}));
     }
 
     @Parameterized.Parameter(value = 0)
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalTest.java
index 80d5024..05b1f6a 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalTest.java
@@ -19,10 +19,13 @@
 package org.apache.tinkerpop.gremlin.process.traversal;
 
 import org.apache.tinkerpop.gremlin.process.remote.traversal.DefaultRemoteTraverser;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalInterruptedException;
 import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
 import org.junit.Test;
 
 import java.util.ArrayList;
@@ -35,11 +38,13 @@
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
 
+import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal;
 import static org.hamcrest.core.Is.is;
 import static org.hamcrest.core.IsCollectionContaining.hasItems;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.fail;
 
 /**
  * @author Stephen Mallette (http://stephen.genoprime.com)
@@ -128,6 +133,16 @@
         assertThat(t.isClosed(), is(true));
     }
 
+    @Test
+    public void shouldOnlyAllowAnonymousChildren() {
+        final GraphTraversalSource g = traversal().withGraph(EmptyGraph.instance());
+        g.V(1).addE("self").to(__.V(1));
+        try {
+            g.V(1).addE("self").to(g.V(1));
+            fail("Should not allow child traversals spawned from 'g'");
+        } catch (IllegalStateException ignored) {}
+    }
+
     private static class MockCloseStep<E> extends MockStep<E> implements AutoCloseable {
         private boolean closed = false;
 
@@ -164,6 +179,11 @@
         }
 
         @Override
+        public boolean hasStarts() {
+            return false;
+        }
+
+        @Override
         public void setPreviousStep(final Step step) {
 
         }
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/GremlinDslProcessorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/GremlinDslProcessorTest.java
index 23876c6..53ff874 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/GremlinDslProcessorTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/GremlinDslProcessorTest.java
@@ -45,7 +45,7 @@
         final Compilation compilation = javac()
                 .withProcessors(new GremlinDslProcessor())
                 .compile(JavaFileObjects.forResource(GremlinDsl.class.getResource("SocialTraversalDsl.java")));
-        assertThat(compilation).succeededWithoutWarnings();
+        assertCompilationSuccess(compilation);
     }
 
     @Test
@@ -53,7 +53,7 @@
         final Compilation compilation = javac()
                 .withProcessors(new GremlinDslProcessor())
                 .compile(JavaFileObjects.forResource(GremlinDsl.class.getResource("SocialMoveTraversalDsl.java")));
-        assertThat(compilation).succeededWithoutWarnings();
+        assertCompilationSuccess(compilation);
         assertThat(compilation)
                 .generatedFile(StandardLocation.SOURCE_OUTPUT, "org.apache.tinkerpop.gremlin.process.traversal.dsl.social", "SocialMoveTraversal.java");
     }
@@ -63,7 +63,7 @@
         final Compilation compilation = javac()
                 .withProcessors(new GremlinDslProcessor())
                 .compile(JavaFileObjects.forResource(GremlinDsl.class.getResource("SocialPackageTraversalDsl.java")));
-        assertThat(compilation).succeededWithoutWarnings();
+        assertCompilationSuccess(compilation);
     }
 
     @Test
@@ -71,7 +71,7 @@
         final Compilation compilation = javac()
                 .withProcessors(new GremlinDslProcessor())
                 .compile(JavaFileObjects.forResource(GremlinDsl.class.getResource("SocialNoDefaultMethodsTraversalDsl.java")));
-        assertThat(compilation).succeededWithoutWarnings();
+        assertCompilationSuccess(compilation);
     }
 
     @Test
@@ -90,6 +90,20 @@
         }
     }
 
+    private void assertCompilationSuccess(final Compilation compilation) {
+        if (isJava8())
+            assertThat(compilation).succeededWithoutWarnings();
+        else {
+            assertThat(compilation).hadWarningContaining("Supported source version 'RELEASE_8' from annotation processor");
+            assertThat(compilation).succeeded();
+        }
+    }
+
+    private boolean isJava8() {
+        String version = System.getProperty("java.version");
+        return version.startsWith("1.");
+    }
+
     static class JavaFileObjectClassLoader extends ClassLoader {
         Map<String, JavaFileObject> classFileMap;
 
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSourceTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSourceTest.java
index ede66cc..fe60d6b 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSourceTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSourceTest.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.dsl.graph;
 
-import org.apache.commons.configuration.MapConfiguration;
+import org.apache.commons.configuration2.MapConfiguration;
 import org.apache.tinkerpop.gremlin.process.remote.RemoteConnection;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy;
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/ElementValueTraversalTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/ElementValueTraversalTest.java
deleted file mode 100644
index 2752a3d..0000000
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/ElementValueTraversalTest.java
+++ /dev/null
@@ -1,78 +0,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.
- */
-package org.apache.tinkerpop.gremlin.process.traversal.lambda;
-
-import org.apache.tinkerpop.gremlin.process.traversal.traverser.B_O_Traverser;
-import org.apache.tinkerpop.gremlin.structure.Edge;
-import org.apache.tinkerpop.gremlin.structure.Vertex;
-import org.apache.tinkerpop.gremlin.structure.VertexProperty;
-import org.junit.Test;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class ElementValueTraversalTest {
-
-    @Test
-    public void shouldWorkOnVertex() {
-        final ElementValueTraversal<Integer> t = new ElementValueTraversal<>("age");
-        final Vertex v = mock(Vertex.class);
-        when(v.value("age")).thenReturn(29);
-        t.addStart(new B_O_Traverser(v, 1).asAdmin());
-        assertEquals(29, t.next().intValue());
-    }
-
-    @Test
-    public void shouldWorkOnEdge() {
-        final ElementValueTraversal<Double> t = new ElementValueTraversal<>("weight");
-        final Edge e = mock(Edge.class);
-        when(e.value("weight")).thenReturn(1.0d);
-        t.addStart(new B_O_Traverser(e, 1).asAdmin());
-        assertEquals(1.0d, t.next(), 0.00001d);
-    }
-
-    @Test
-    public void shouldWorkOnVertexProperty() {
-        final ElementValueTraversal<Integer> t = new ElementValueTraversal<>("age");
-        final VertexProperty vp = mock(VertexProperty.class);
-        when(vp.value("age")).thenReturn(29);
-        t.addStart(new B_O_Traverser(vp, 1).asAdmin());
-        assertEquals(29, t.next().intValue());
-    }
-
-    @Test
-    public void shouldWorkOnMap() {
-        final ElementValueTraversal<Integer> t = new ElementValueTraversal<>("age");
-        final Map<String,Integer> m = new HashMap<>();
-        m.put("age", 29);
-        t.addStart(new B_O_Traverser(m, 1).asAdmin());
-        assertEquals(29, t.next().intValue());
-    }
-
-    @Test(expected = IllegalStateException.class)
-    public void shouldThrowExceptionWhenTryingUnsupportedType() {
-        final ElementValueTraversal<Integer> t = new ElementValueTraversal<>("age");
-        t.addStart(new B_O_Traverser(29, 1).asAdmin());
-        t.next();
-    }
-}
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/TokenTraversalTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/TokenTraversalTest.java
new file mode 100644
index 0000000..7d1ad54
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/TokenTraversalTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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.lambda;
+
+import org.apache.tinkerpop.gremlin.process.traversal.traverser.B_O_Traverser;
+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.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class TokenTraversalTest {
+    @Test
+    public void shouldWorkOnVertex() {
+        final TokenTraversal<Vertex, Integer> t = new TokenTraversal<>(T.id);
+        final Vertex v = mock(Vertex.class);
+        when(v.id()).thenReturn(100);
+        t.addStart(new B_O_Traverser<>(v, 1).asAdmin());
+        assertEquals(100, t.next().intValue());
+    }
+
+    @Test
+    public void shouldWorkOnVertexProperty() {
+        final TokenTraversal<VertexProperty, Integer> t = new TokenTraversal<>(T.id);
+        final VertexProperty vo = mock(VertexProperty.class);
+        when(vo.id()).thenReturn(100);
+        t.addStart(new B_O_Traverser<>(vo, 1).asAdmin());
+        assertEquals(100, t.next().intValue());
+    }
+
+    @Test
+    public void shouldWorkOnEdge() {
+        final TokenTraversal<Edge, Integer> t = new TokenTraversal<>(T.id);
+        final Edge e = mock(Edge.class);
+        when(e.id()).thenReturn(100);
+        t.addStart(new B_O_Traverser<>(e, 1).asAdmin());
+        assertEquals(100, t.next().intValue());
+    }
+
+    @Test
+    public void shouldWorkOnPropertyKey() {
+        final TokenTraversal<Property<String>, String> t = new TokenTraversal<>(T.key);
+        final Property<String> p = mock(Property.class);
+        when(p.key()).thenReturn("name");
+        t.addStart(new B_O_Traverser<>(p, 1).asAdmin());
+        assertEquals("name", t.next());
+    }
+
+    @Test
+    public void shouldWorkOnPropertyValue() {
+        final TokenTraversal<Property<String>, String> t = new TokenTraversal<>(T.value);
+        final Property<String> p = mock(Property.class);
+        when(p.value()).thenReturn("marko");
+        t.addStart(new B_O_Traverser<>(p, 1).asAdmin());
+        assertEquals("marko", t.next());
+    }
+}
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/ValueTraversalTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/ValueTraversalTest.java
new file mode 100644
index 0000000..761d0b6
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/ValueTraversalTest.java
@@ -0,0 +1,118 @@
+/*
+ * 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.lambda;
+
+import org.apache.tinkerpop.gremlin.process.traversal.traverser.B_O_Traverser;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Property;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedProperty;
+import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertexProperty;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class ValueTraversalTest {
+
+    @Test
+    public void shouldWorkOnVertex() {
+        final ValueTraversal<Vertex, Integer> t = new ValueTraversal<>("age");
+        final Vertex v = mock(Vertex.class);
+        when(v.property("age")).thenReturn(new DetachedVertexProperty<>(1, "age", 29, null));
+        t.addStart(new B_O_Traverser<>(v, 1).asAdmin());
+        assertEquals(29, t.next().intValue());
+    }
+
+    @Test
+    public void shouldWorkOnVertexWithMissingKey() {
+        final ValueTraversal<Vertex, Integer> t = new ValueTraversal<>("age");
+        final Vertex v = mock(Vertex.class);
+        when(v.property("age")).thenReturn(VertexProperty.empty());
+        t.addStart(new B_O_Traverser<>(v, 1).asAdmin());
+        assertNull(t.next());
+    }
+
+    @Test
+    public void shouldWorkOnEdge() {
+        final ValueTraversal<Edge, Double> t = new ValueTraversal<>("weight");
+        final Edge e = mock(Edge.class);
+        when(e.property("weight")).thenReturn(new DetachedProperty<>("weight", 1.0d));
+        t.addStart(new B_O_Traverser<>(e, 1).asAdmin());
+        assertEquals(1.0d, t.next(), 0.00001d);
+    }
+
+    @Test
+    public void shouldWorkOnEdgeWithMissingKey() {
+        final ValueTraversal<Edge, Double> t = new ValueTraversal<>("weight");
+        final Edge e = mock(Edge.class);
+        when(e.property("weight")).thenReturn(Property.empty());
+        t.addStart(new B_O_Traverser<>(e, 1).asAdmin());
+        assertNull(t.next());
+    }
+
+    @Test
+    public void shouldWorkOnVertexProperty() {
+        final ValueTraversal<VertexProperty, Integer> t = new ValueTraversal<>("age");
+        final VertexProperty vp = mock(VertexProperty.class);
+        when(vp.property("age")).thenReturn(new DetachedProperty<>("age", 29));
+        t.addStart(new B_O_Traverser<>(vp, 1).asAdmin());
+        assertEquals(29, t.next().intValue());
+    }
+
+    @Test
+    public void shouldWorkOnVertexPropertyWithMissingKey() {
+        final ValueTraversal<VertexProperty, Integer> t = new ValueTraversal<>("age");
+        final VertexProperty vp = mock(VertexProperty.class);
+        when(vp.property("age")).thenReturn(Property.empty());
+        t.addStart(new B_O_Traverser<>(vp, 1).asAdmin());
+        assertNull(t.next());
+    }
+
+    @Test
+    public void shouldWorkOnMap() {
+        final ValueTraversal<Map<String,Integer>, Integer> t = new ValueTraversal<>("age");
+        final Map<String,Integer> m = new HashMap<>();
+        m.put("age", 29);
+        t.addStart(new B_O_Traverser<>(m, 1).asAdmin());
+        assertEquals(29, t.next().intValue());
+    }
+
+    @Test
+    public void shouldWorkOnMapWithMissingKey() {
+        final ValueTraversal<Map<String,Integer>, Integer> t = new ValueTraversal<>("not-age");
+        final Map<String,Integer> m = new HashMap<>();
+        m.put("age", 29);
+        t.addStart(new B_O_Traverser<>(m, 1).asAdmin());
+        assertNull(t.next());
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void shouldThrowExceptionWhenTryingUnsupportedType() {
+        final ValueTraversal<Integer, Integer> t = new ValueTraversal<>("age");
+        t.addStart(new B_O_Traverser<>(29, 1).asAdmin());
+        t.next();
+    }
+}
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStepTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStepTest.java
new file mode 100644
index 0000000..d5ae0ec
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStepTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.structure.T;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.util.function.TraverserSetSupplier;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class AddVertexStepTest {
+
+    @Test
+    public void shouldDefaultTheLabelIfNullString() {
+        final Traversal.Admin t = mock(Traversal.Admin.class);
+        when(t.getTraverserSetSupplier()).thenReturn(TraverserSetSupplier.instance());
+        final AddVertexStartStep starStep = new AddVertexStartStep(t, (String) null);
+        assertEquals(Vertex.DEFAULT_LABEL, starStep.getParameters().getRaw().get(T.label).get(0));
+        final AddVertexStep step = new AddVertexStep(t, (String) null);
+        assertEquals(Vertex.DEFAULT_LABEL, starStep.getParameters().getRaw().get(T.label).get(0));
+    }
+
+    @Test
+    public void shouldDefaultTheLabelIfNullTraversal() {
+        final Traversal.Admin t = mock(Traversal.Admin.class);
+        when(t.getTraverserSetSupplier()).thenReturn(TraverserSetSupplier.instance());
+        final AddVertexStartStep starStep = new AddVertexStartStep(t, (Traversal<?,String>) null);
+        assertEquals(Vertex.DEFAULT_LABEL, starStep.getParameters().getRaw().get(T.label).get(0));
+        final AddVertexStep step = new AddVertexStep(t, (String) null);
+        assertEquals(Vertex.DEFAULT_LABEL, starStep.getParameters().getRaw().get(T.label).get(0));
+    }
+}
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderGlobalStepTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderGlobalStepTest.java
index 31457fc..8ba2c52 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderGlobalStepTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderGlobalStepTest.java
@@ -40,12 +40,6 @@
     protected List<Traversal> getTraversals() {
         return Arrays.asList(
                 __.order(),
-                __.order().by(Order.decr),
-                __.order().by("age", Order.incr),
-                __.order().by("age", Order.decr),
-                __.order().by(outE().count(), Order.incr),
-                __.order().by("age", Order.incr).by(outE().count(), Order.incr),
-                __.order().by(outE().count(), Order.incr).by("age", Order.incr),
                 __.order().by(Order.desc),
                 __.order().by("age", Order.asc),
                 __.order().by("age", Order.desc),
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderLocalStepTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderLocalStepTest.java
index 5999793..ec5e539 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderLocalStepTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderLocalStepTest.java
@@ -42,12 +42,6 @@
     protected List<Traversal> getTraversals() {
         return Arrays.asList(
                 __.order(Scope.local),
-                __.order(Scope.local).by(Order.decr),
-                __.order(Scope.local).by("age", Order.incr),
-                __.order(Scope.local).by("age", Order.decr),
-                __.order(Scope.local).by(outE().count(), Order.incr),
-                __.order(Scope.local).by("age", Order.incr).by(outE().count(), Order.incr),
-                __.order(Scope.local).by(outE().count(), Order.incr).by("age", Order.incr),
                 __.order(Scope.local).by(Order.desc),
                 __.order(Scope.local).by("age", Order.asc),
                 __.order(Scope.local).by("age", Order.desc),
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateGlobalStepTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateGlobalStepTest.java
new file mode 100644
index 0000000..f34f420
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateGlobalStepTest.java
@@ -0,0 +1,40 @@
+/*
+ * 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.sideEffect;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.process.traversal.step.StepTest;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author Daniel Kuppitz (http://gremlin.guru)
+ */
+public class AggregateGlobalStepTest extends StepTest {
+
+    @Override
+    protected List<Traversal> getTraversals() {
+        return Arrays.asList(
+                __.aggregate("x"),
+                __.aggregate("x").by("name"),
+                __.aggregate("x").by("age"));
+    }
+}
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateLocalStepTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateLocalStepTest.java
new file mode 100644
index 0000000..9128292
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateLocalStepTest.java
@@ -0,0 +1,40 @@
+/*
+ * 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.sideEffect;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.process.traversal.step.StepTest;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author Daniel Kuppitz (http://gremlin.guru)
+ */
+public class AggregateLocalStepTest extends StepTest {
+
+    @Override
+    protected List<Traversal> getTraversals() {
+        return Arrays.asList(
+                __.store("x"),
+                __.store("x").by("name"),
+                __.store("x").by("age"));
+    }
+}
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateStepTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateStepTest.java
deleted file mode 100644
index 2c0101c..0000000
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateStepTest.java
+++ /dev/null
@@ -1,40 +0,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.
- */
-package org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect;
-
-import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
-import org.apache.tinkerpop.gremlin.process.traversal.step.StepTest;
-
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * @author Daniel Kuppitz (http://gremlin.guru)
- */
-public class AggregateStepTest extends StepTest {
-
-    @Override
-    protected List<Traversal> getTraversals() {
-        return Arrays.asList(
-                __.aggregate("x"),
-                __.aggregate("x").by("name"),
-                __.aggregate("x").by("age"));
-    }
-}
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/StoreStepTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/StoreStepTest.java
deleted file mode 100644
index be3ec8e..0000000
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/StoreStepTest.java
+++ /dev/null
@@ -1,40 +0,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.
- */
-package org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect;
-
-import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
-import org.apache.tinkerpop.gremlin.process.traversal.step.StepTest;
-
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * @author Daniel Kuppitz (http://gremlin.guru)
- */
-public class StoreStepTest extends StepTest {
-
-    @Override
-    protected List<Traversal> getTraversals() {
-        return Arrays.asList(
-                __.store("x"),
-                __.store("x").by("name"),
-                __.store("x").by("age"));
-    }
-}
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/ParametersTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/ParametersTest.java
index ebe40af..27d8e44 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/ParametersTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/ParametersTest.java
@@ -43,6 +43,7 @@
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
 public class ParametersTest {
+
     @Test
     public void shouldGetKeyValuesEmpty() {
         final Parameters parameters = new Parameters();
@@ -50,6 +51,16 @@
     }
 
     @Test
+    public void shouldAllowNullValues() {
+        final Parameters parameters = new Parameters();
+        parameters.set(null, "a", null, "b", "bat", "c", "cat");
+
+        final Object[] params = parameters.getKeyValues(mock(Traverser.Admin.class));
+        assertEquals(6, params.length);
+        assertThat(Arrays.equals(new Object[] {"a", null, "b", "bat", "c", "cat"}, params), is(true));
+    }
+
+    @Test
     public void shouldGetKeyValues() {
         final Parameters parameters = new Parameters();
         parameters.set(null, "a", "axe", "b", "bat", "c", "cat");
@@ -210,6 +221,14 @@
     }
 
     @Test
+    public void shouldContainKeyValue() {
+        final Parameters parameters = new Parameters();
+        parameters.set(null, "a", "axe", "b", "bat", "c", "cat");
+
+        assertThat(parameters.contains("b", "bat"), is(true));
+    }
+
+    @Test
     public void shouldNotContainKey() {
         final Parameters parameters = new Parameters();
         parameters.set(null, "a", "axe", "b", "bat", "c", "cat");
@@ -218,6 +237,14 @@
     }
 
     @Test
+    public void shouldNotContainKeyAndValue() {
+        final Parameters parameters = new Parameters();
+        parameters.set(null, "a", "axe", "b", "bat", "c", "cat");
+
+        assertThat(parameters.contains("b", "mat"), is(false));
+    }
+
+    @Test
     public void shouldGetSetMultiple() {
         final Parameters parameters = new Parameters();
         parameters.set(null, "a", "axe", "a", "ant", "b", "bat", "b", "ball", "c", "cat");
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/ConnectiveStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/ConnectiveStrategyTest.java
index a8211e0..cffac71 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/ConnectiveStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/ConnectiveStrategyTest.java
@@ -39,7 +39,7 @@
 @RunWith(Parameterized.class)
 public class ConnectiveStrategyTest {
 
-    private static final Translator<String,String> translator = GroovyTranslator.of("__");
+    private static final Translator.ScriptTranslator translator = GroovyTranslator.of("__");
 
     @Parameterized.Parameter(value = 0)
     public Traversal.Admin original;
@@ -56,7 +56,7 @@
 
     @Test
     public void doTest() {
-        final String repr = translator.translate(original.getBytecode());
+        final String repr = translator.translate(original.getBytecode()).getScript();
         applyConnectiveStrategy(original);
         assertEquals(repr, optimized, original);
     }
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/ElementIdStrategyTraverseTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/ElementIdStrategyTraverseTest.java
index b4b20c8..d1793da 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/ElementIdStrategyTraverseTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/ElementIdStrategyTraverseTest.java
@@ -49,7 +49,7 @@
 @RunWith(Parameterized.class)
 public class ElementIdStrategyTraverseTest {
     private static Traversal traversalWithAddV;
-    private static final Translator<String,String> translator = GroovyTranslator.of("__");
+    private static final Translator.ScriptTranslator translator = GroovyTranslator.of("__");
 
     static {
         final Graph mockedGraph = mock(Graph.class);
@@ -85,7 +85,7 @@
 
     @Test
     public void shouldAlterTraversalToIncludeIdWhereNecessary() {
-        final String repr = translator.translate(traversal.getBytecode());
+        final String repr = translator.translate(traversal.getBytecode()).getScript();
         final ElementIdStrategy strategy = ElementIdStrategy.build().create();
         strategy.apply(traversal.asAdmin());
 
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/EventStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/EventStrategyTest.java
index f06b1a8..a5896e8 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/EventStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/EventStrategyTest.java
@@ -41,7 +41,7 @@
  */
 @RunWith(Parameterized.class)
 public class EventStrategyTest {
-    private static final Translator<String,String> translator = GroovyTranslator.of("__");
+    private static final Translator.ScriptTranslator translator = GroovyTranslator.of("__");
 
     @Parameterized.Parameters(name = "{0}")
     public static Iterable<Object[]> data() {
@@ -69,7 +69,7 @@
 
     @Test
     public void shouldEventOnMutatingSteps() {
-        final String repr = translator.translate(traversal.getBytecode());
+        final String repr = translator.translate(traversal.getBytecode()).getScript();
         final MutationListener listener1 = new ConsoleMutationListener(EmptyGraph.instance());
         final EventStrategy eventStrategy = EventStrategy.build()
                 .addListener(listener1).create();
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/PartitionStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/PartitionStrategyTest.java
index afcd4a6..7bc80b3 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/PartitionStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/PartitionStrategyTest.java
@@ -62,7 +62,7 @@
 
     @RunWith(Parameterized.class)
     public static class PartitionStrategyTraverseTest {
-        private static final Translator<String,String> translator = GroovyTranslator.of("__");
+        private static final Translator.ScriptTranslator translator = GroovyTranslator.of("__");
 
         @Parameterized.Parameters(name = "{0}")
         public static Iterable<Object[]> data() {
@@ -101,7 +101,7 @@
 
         @Test
         public void shouldIncludeAdditionalHasStepsAndAppendPartitionOnMutatingSteps() {
-            final String repr = translator.translate(traversal.getBytecode());
+            final String repr = translator.translate(traversal.getBytecode()).getScript();
             final PartitionStrategy strategy = PartitionStrategy.build()
                     .partitionKey("p").writePartition("a").readPartitions("a").create();
 
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/ReferenceElementStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/ReferenceElementStrategyTest.java
index ac4ec52..d689972 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/ReferenceElementStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/ReferenceElementStrategyTest.java
@@ -38,7 +38,7 @@
  */
 public class ReferenceElementStrategyTest {
 
-    private static final GraphTraversalSource g = traversal().withGraph(EmptyGraph.instance()).
+    private static final GraphTraversalSource g = traversal().withEmbedded(EmptyGraph.instance()).
             withStrategies(ReferenceElementStrategy.instance());
 
     @Test
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategyTest.java
index 5f6c82d..5147e8f 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategyTest.java
@@ -70,7 +70,7 @@
  */
 @RunWith(Enclosed.class)
 public class SubgraphStrategyTest {
-    private static final Translator<String,String> translator = GroovyTranslator.of("__");
+    private static final Translator.ScriptTranslator translator = GroovyTranslator.of("__");
 
     @RunWith(Parameterized.class)
     public static class TraverseTest {
@@ -105,7 +105,7 @@
 
         @Test
         public void shouldSubgraph() {
-            final String repr = translator.translate(traversal.getBytecode());
+            final String repr = translator.translate(traversal.getBytecode()).getScript();
             final SubgraphStrategy strategy = SubgraphStrategy.build().edges(__.has("edge")).vertices(__.has("vertex")).create();
             strategy.apply(traversal);
 
@@ -125,7 +125,7 @@
 
         @Test
         public void doTest() {
-            final String repr = translator.translate(original.getBytecode());
+            final String repr = translator.translate(original.getBytecode()).getScript();
             final TraversalStrategies originalStrategies = new DefaultTraversalStrategies();
             originalStrategies.addStrategies(SubgraphStrategy.build().
                     vertices(__.and(has("name", "marko"), has("age", 29))).
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/VertexProgramStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/VertexProgramStrategyTest.java
index ecc4708..5edeff4 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/VertexProgramStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/VertexProgramStrategyTest.java
@@ -48,7 +48,7 @@
  */
 @RunWith(Parameterized.class)
 public class VertexProgramStrategyTest {
-    private static final Translator<String,String> translator = GroovyTranslator.of("__");
+    private static final Translator.ScriptTranslator translator = GroovyTranslator.of("__");
 
     @Parameterized.Parameter(value = 0)
     public Traversal.Admin original;
@@ -59,7 +59,7 @@
 
     @Test
     public void doTest() {
-        final String repr = translator.translate(original.getBytecode());
+        final String repr = translator.translate(original.getBytecode()).getScript();
         final TraversalStrategies strategies = new DefaultTraversalStrategies();
         strategies.addStrategies(new VertexProgramStrategy(Computer.compute()), ComputerVerificationStrategy.instance());
         original.asAdmin().setStrategies(strategies);
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/AdjacentToIncidentStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/AdjacentToIncidentStrategyTest.java
index 62345ab..b21ac6f 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/AdjacentToIncidentStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/AdjacentToIncidentStrategyTest.java
@@ -37,7 +37,7 @@
  */
 @RunWith(Parameterized.class)
 public class AdjacentToIncidentStrategyTest {
-    private static final Translator<String,String> translator = GroovyTranslator.of("__");
+    private static final Translator.ScriptTranslator translator = GroovyTranslator.of("__");
 
     @Parameterized.Parameter(value = 0)
     public Traversal.Admin original;
@@ -55,7 +55,7 @@
 
     @Test
     public void doTest() {
-        final String repr = translator.translate(original.getBytecode());
+        final String repr = translator.translate(original.getBytecode()).getScript();
         applyAdjacentToIncidentStrategy(original);
         assertEquals(repr, optimized, original);
     }
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/ByModulatorOptimizationStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/ByModulatorOptimizationStrategyTest.java
new file mode 100644
index 0000000..53f87ff
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/ByModulatorOptimizationStrategyTest.java
@@ -0,0 +1,193 @@
+/*
+ * 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.strategy.optimization;
+
+import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.Scope;
+import org.apache.tinkerpop.gremlin.process.traversal.Translator;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.process.traversal.translator.GroovyTranslator;
+import org.apache.tinkerpop.gremlin.process.traversal.util.DefaultTraversalStrategies;
+import org.apache.tinkerpop.gremlin.structure.T;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.apache.tinkerpop.gremlin.process.traversal.Operator.assign;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.values;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author Daniel Kuppitz (http://gremlin.guru)
+ */
+@RunWith(Parameterized.class)
+public class ByModulatorOptimizationStrategyTest {
+    private static final Translator.ScriptTranslator translator = GroovyTranslator.of("__");
+
+    @Parameterized.Parameter
+    public Traversal.Admin original;
+
+    @Parameterized.Parameter(value = 1)
+    public Traversal optimized;
+
+    @Parameterized.Parameters(name = "{0}")
+    public static Iterable<Object[]> generateTestParameters() {
+
+        final List<Object[]> originalAndOptimized = new ArrayList<>();
+        final GraphTraversal[] baseTraversals = new GraphTraversal[]{
+                __.aggregate("x"),
+                __.dedup(),
+                __.dedup("a"),
+                __.group(),
+                __.group("x"),
+                __.groupCount(),
+                __.groupCount("x"),
+                __.order(),
+                __.order(Scope.local),
+                __.project("a"),
+                __.path(),
+                __.path().from("a").to("b"),
+                __.sack(assign),
+                __.sample(10),
+                __.select("a"),
+                __.select("a", "b"),
+                __.store("x"),
+                __.tree(),
+                __.tree("x"),
+                __.where(P.eq("a")),
+                __.where("a", P.eq("b"))
+        };
+
+        for (final Traversal traversal : baseTraversals) {
+            originalAndOptimized.add(new Traversal[]{
+                    ((GraphTraversal<?, ?>) traversal.asAdmin().clone()).by(values("name")),
+                    ((GraphTraversal) traversal.asAdmin().clone()).by("name"),
+            });
+            originalAndOptimized.add(new Traversal[]{
+                    ((GraphTraversal<?, ?>) traversal.asAdmin().clone()).by(__.id()),
+                    ((GraphTraversal) traversal.asAdmin().clone()).by(T.id),
+            });
+            originalAndOptimized.add(new Traversal[]{
+                    ((GraphTraversal<?, ?>) traversal.asAdmin().clone()).by(__.label()),
+                    ((GraphTraversal) traversal.asAdmin().clone()).by(T.label),
+            });
+            originalAndOptimized.add(new Traversal[]{
+                    ((GraphTraversal<?, ?>) traversal.asAdmin().clone()).by(__.key()),
+                    ((GraphTraversal) traversal.asAdmin().clone()).by(T.key),
+            });
+            originalAndOptimized.add(new Traversal[]{
+                    ((GraphTraversal<?, ?>) traversal.asAdmin().clone()).by(__.value()),
+                    ((GraphTraversal) traversal.asAdmin().clone()).by(T.value),
+            });
+            originalAndOptimized.add(new Traversal[]{
+                    ((GraphTraversal<?, ?>) traversal.asAdmin().clone()).by(__.identity()),
+                    ((GraphTraversal) traversal.asAdmin().clone()).by(),
+            });
+        }
+
+        originalAndOptimized.add(new Traversal[]{
+                __.project("a", "b", "c", "d", "e")
+                        .by(values("name"))
+                        .by(__.id())
+                        .by(__.label())
+                        .by(__.identity())
+                        .by(__.outE().count()),
+                __.project("a", "b", "c", "d", "e")
+                        .by("name")
+                        .by(T.id)
+                        .by(T.label)
+                        .by()
+                        .by(__.outE().count())
+        });
+
+        final GraphTraversal[] baseGroupTraversals = new GraphTraversal[]{
+                __.group().by("age"),
+                __.group("x").by("age"),
+        };
+
+        for (final Traversal traversal : baseGroupTraversals) {
+            originalAndOptimized.add(new Traversal[]{
+                    ((GraphTraversal<?, ?>) traversal.asAdmin().clone()).by(values("name").fold()),
+                    ((GraphTraversal) traversal.asAdmin().clone()).by("name"),
+            });
+            originalAndOptimized.add(new Traversal[]{
+                    ((GraphTraversal<?, ?>) traversal.asAdmin().clone()).by(__.id().fold()),
+                    ((GraphTraversal) traversal.asAdmin().clone()).by(T.id),
+            });
+            originalAndOptimized.add(new Traversal[]{
+                    ((GraphTraversal<?, ?>) traversal.asAdmin().clone()).by(__.label().fold()),
+                    ((GraphTraversal) traversal.asAdmin().clone()).by(T.label),
+            });
+            originalAndOptimized.add(new Traversal[]{
+                    ((GraphTraversal<?, ?>) traversal.asAdmin().clone()).by(__.key().fold()),
+                    ((GraphTraversal) traversal.asAdmin().clone()).by(T.key),
+            });
+            originalAndOptimized.add(new Traversal[]{
+                    ((GraphTraversal<?, ?>) traversal.asAdmin().clone()).by(__.value().fold()),
+                    ((GraphTraversal) traversal.asAdmin().clone()).by(T.value),
+            });
+            originalAndOptimized.add(new Traversal[]{
+                    ((GraphTraversal<?, ?>) traversal.asAdmin().clone()).by(__.identity()),
+                    ((GraphTraversal) traversal.asAdmin().clone()).by(),
+            });
+        }
+
+        originalAndOptimized.add(new Traversal[]{
+                __.group().by(values("age")).by(values("name")),
+                __.group().by("age").by(values("name"))
+        });
+
+        originalAndOptimized.add(new Traversal[]{
+                __.group("x").by(values("age")).by(values("name")),
+                __.group("x").by("age").by(values("name"))
+        });
+
+        originalAndOptimized.add(new Traversal[]{
+                __.group().by(values("age")).by(values("name").fold()),
+                __.group().by("age").by("name")
+        });
+
+        originalAndOptimized.add(new Traversal[]{
+                __.group("x").by(values("age")).by(values("name").fold()),
+                __.group("x").by("age").by("name")
+        });
+
+        return originalAndOptimized;
+    }
+
+    private void applyByModulatorOptimizationStrategy(final Traversal traversal) {
+        final TraversalStrategies strategies = new DefaultTraversalStrategies();
+        strategies.addStrategies(ByModulatorOptimizationStrategy.instance());
+        traversal.asAdmin().setStrategies(strategies);
+        traversal.asAdmin().applyStrategies();
+    }
+
+    @Test
+    public void doTest() {
+        final String repr = translator.translate(original.getBytecode()).getScript();
+        applyByModulatorOptimizationStrategy(original);
+        assertEquals(repr, optimized, original);
+    }
+}
\ No newline at end of file
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/CountStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/CountStrategyTest.java
index b4d14d7..8ea0a65 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/CountStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/CountStrategyTest.java
@@ -47,7 +47,7 @@
  */
 @RunWith(Parameterized.class)
 public class CountStrategyTest {
-    private static final Translator<String,String> translator = GroovyTranslator.of("__");
+    private static final Translator.ScriptTranslator translator = GroovyTranslator.of("__");
 
     @Parameterized.Parameter(value = 0)
     public Traversal.Admin original;
@@ -117,7 +117,7 @@
 
     @Test
     public void doTest() {
-        final String repr = translator.translate(original.getBytecode());
+        final String repr = translator.translate(original.getBytecode()).getScript();
         applyCountStrategy(original);
         assertEquals(repr, optimized, original);
     }
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/EarlyLimitStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/EarlyLimitStrategyTest.java
index ea0b95c..d6578dd 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/EarlyLimitStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/EarlyLimitStrategyTest.java
@@ -43,7 +43,7 @@
  */
 @RunWith(Parameterized.class)
 public class EarlyLimitStrategyTest {
-    private static final Translator<String,String> translator = GroovyTranslator.of("__");
+    private static final Translator.ScriptTranslator translator = GroovyTranslator.of("__");
 
     @Parameterized.Parameter()
     public Traversal.Admin original;
@@ -56,7 +56,7 @@
 
     @Test
     public void doTest() {
-        final String repr = translator.translate(original.getBytecode());
+        final String repr = translator.translate(original.getBytecode()).getScript();
         final TraversalStrategies strategies = new DefaultTraversalStrategies();
         strategies.addStrategies(EarlyLimitStrategy.instance());
         for (final TraversalStrategy strategy : this.otherStrategies) {
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategyTest.java
index d7e1a33..5ebc52c 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategyTest.java
@@ -54,7 +54,7 @@
  */
 @RunWith(Parameterized.class)
 public class FilterRankingStrategyTest {
-    private static final Translator<String,String> translator = GroovyTranslator.of("__");
+    private static final Translator.ScriptTranslator translator = GroovyTranslator.of("__");
 
     public static Iterable<Object[]> data() {
         return generateTestParameters();
@@ -71,7 +71,7 @@
 
     @Test
     public void doTest() {
-        final String repr = translator.translate(original.getBytecode());
+        final String repr = translator.translate(original.getBytecode()).getScript();
         final TraversalStrategies strategies = new DefaultTraversalStrategies();
         strategies.addStrategies(FilterRankingStrategy.instance());
         for (final TraversalStrategy strategy : this.otherStrategies) {
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/IdentityRemovalStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/IdentityRemovalStrategyTest.java
index 09d9444..759a17d 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/IdentityRemovalStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/IdentityRemovalStrategyTest.java
@@ -30,6 +30,9 @@
 
 import java.util.Arrays;
 
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.inE;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.outE;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.union;
 import static org.junit.Assert.assertEquals;
 
 /**
@@ -37,7 +40,7 @@
  */
 @RunWith(Parameterized.class)
 public class IdentityRemovalStrategyTest {
-    private static final Translator<String,String> translator = GroovyTranslator.of("__");
+    private static final Translator.ScriptTranslator translator = GroovyTranslator.of("__");
 
     @Parameterized.Parameter(value = 0)
     public Traversal.Admin original;
@@ -45,32 +48,37 @@
     @Parameterized.Parameter(value = 1)
     public Traversal optimized;
 
-    private void applyIdentityRemovalStrategy(final Traversal traversal) {
-        final TraversalStrategies strategies = new DefaultTraversalStrategies();
-        strategies.addStrategies(IdentityRemovalStrategy.instance());
-        traversal.asAdmin().setStrategies(strategies);
-        traversal.asAdmin().applyStrategies();
-
-    }
-
-    @Test
-    public void doTest() {
-        final String repr = translator.translate(original.getBytecode());
-        applyIdentityRemovalStrategy(original);
-        assertEquals(repr, optimized, original);
-    }
-
     @Parameterized.Parameters(name = "{0}")
     public static Iterable<Object[]> generateTestParameters() {
 
         return Arrays.asList(new Traversal[][]{
                 {__.identity(), __.identity()},
                 {__.identity().out(), __.out()},
+                {__.identity().out().identity().identity(), __.out()},
+                {__.match(__.as("a").out("knows").identity().as("b"),__.as("b").identity()).identity(), __.match(__.as("a").out("knows").as("b"),__.as("b"))},
+                {__.union(__.out().identity(), __.identity(), __.out()), __.union(__.out(), __.identity(), __.out())},
+                {__.choose(__.out().identity(), __.identity(), __.out("knows")), __.choose(__.out(), __.identity(), __.out("knows"))},
                 {__.identity().out().identity(), __.out()},
                 {__.identity().as("a").out().identity(), __.identity().as("a").out()},
                 {__.identity().as("a").out().identity().as("b"), __.identity().as("a").out().as("b")},
                 {__.identity().as("a").out().in().identity().identity().as("b").identity().out(), __.identity().as("a").out().in().as("b").out()},
                 {__.out().identity().as("a").out().in().identity().identity().as("b").identity().out(), __.out().as("a").out().in().as("b").out()},
+                {__.V(1, 2).local(union(outE().count(), inE().count(), (Traversal) outE().values("weight").sum())), __.V(1, 2).local(union(outE().count(), inE().count(), (Traversal) outE().values("weight").sum()))}
         });
     }
+
+    @Test
+    public void doTest() {
+        final String repr = translator.translate(original.getBytecode()).getScript();
+        applyIdentityRemovalStrategy(original);
+        assertEquals(repr, optimized, original);
+    }
+
+    private void applyIdentityRemovalStrategy(final Traversal traversal) {
+        final TraversalStrategies strategies = new DefaultTraversalStrategies();
+        strategies.addStrategies(IdentityRemovalStrategy.instance());
+        traversal.asAdmin().setStrategies(strategies);
+        traversal.asAdmin().applyStrategies();
+
+    }
 }
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/IncidentToAdjacentStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/IncidentToAdjacentStrategyTest.java
index ca1342b..9d25a90 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/IncidentToAdjacentStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/IncidentToAdjacentStrategyTest.java
@@ -40,7 +40,7 @@
  */
 @RunWith(Parameterized.class)
 public class IncidentToAdjacentStrategyTest {
-    private static final Translator<String,String> translator = GroovyTranslator.of("__");
+    private static final Translator.ScriptTranslator translator = GroovyTranslator.of("__");
 
     @Parameterized.Parameter(value = 0)
     public Traversal.Admin original;
@@ -74,7 +74,7 @@
 
     @Test
     public void doTest() {
-        final String repr = translator.translate(original.getBytecode());
+        final String repr = translator.translate(original.getBytecode()).getScript();
         final TraversalStrategies strategies = new DefaultTraversalStrategies();
         strategies.addStrategies(IncidentToAdjacentStrategy.instance());
         this.original.asAdmin().setStrategies(strategies);
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategyTest.java
index e7f9835..7596f49 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategyTest.java
@@ -67,7 +67,7 @@
  */
 @RunWith(Parameterized.class)
 public class InlineFilterStrategyTest {
-    private static final Translator<String,String> translator = GroovyTranslator.of("__");
+    private static final Translator.ScriptTranslator translator = GroovyTranslator.of("__");
 
     @Parameterized.Parameter(value = 0)
     public Traversal.Admin original;
@@ -80,7 +80,7 @@
 
     @Test
     public void doTest() {
-        final String repr = translator.translate(original.getBytecode());
+        final String repr = translator.translate(original.getBytecode()).getScript();
         final TraversalStrategies strategies = new DefaultTraversalStrategies();
         strategies.addStrategies(InlineFilterStrategy.instance());
 
@@ -102,7 +102,8 @@
                 {filter(has("age", gt(10)).as("b")).as("a"), has("age", gt(10)).as("b", "a"), Collections.emptyList()},
                 {filter(has("age", gt(10)).as("a")), has("age", gt(10)).as("a"), Collections.emptyList()},
                 {filter(and(has("age", gt(10)).as("a"), has("name", "marko"))), addHas(__.start(), "age", gt(10), "name", eq("marko")).as("a"), Collections.emptyList()},
-                {filter(out("created").and().out("knows").or().in("knows")), filter(or(and(out("created"), out("knows")), __.in("knows"))), Collections.singletonList(ConnectiveStrategy.instance())},
+                {filter(out("created").and().out("knows").or().in("knows")), or(and(out("created"), out("knows")), __.in("knows")), Collections.singletonList(ConnectiveStrategy.instance())},
+                {filter(out("created").and().out("knows").or().in("knows")).and(hasLabel("person")), or(and(out("created"), out("knows")), __.in("knows")).hasLabel("person"), Collections.singletonList(ConnectiveStrategy.instance())},
                 //
                 {or(has("name", "marko"), has("age", 32)), or(has("name", "marko"), has("age", 32)), Collections.emptyList()},
                 {or(has("name", "marko"), has("name", "bob")), has("name", eq("marko").or(eq("bob"))), Collections.emptyList()},
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/LazyBarrierStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/LazyBarrierStrategyTest.java
index b6f461c..9a43058 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/LazyBarrierStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/LazyBarrierStrategyTest.java
@@ -41,7 +41,7 @@
  */
 @RunWith(Parameterized.class)
 public class LazyBarrierStrategyTest {
-    private static final Translator<String,String> translator = GroovyTranslator.of("__");
+    private static final Translator.ScriptTranslator translator = GroovyTranslator.of("__");
 
     @Parameterized.Parameters(name = "{0}")
     public static Iterable<Object[]> data() {
@@ -59,7 +59,7 @@
 
     @Test
     public void doTest() {
-        final String repr = translator.translate(original.getBytecode());
+        final String repr = translator.translate(original.getBytecode()).getScript();
         final TraversalStrategies strategies = new DefaultTraversalStrategies();
         strategies.addStrategies(LazyBarrierStrategy.instance());
         for (final TraversalStrategy strategy : this.otherStrategies) {
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/MatchPredicateStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/MatchPredicateStrategyTest.java
index cec76b6..00dc8fc 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/MatchPredicateStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/MatchPredicateStrategyTest.java
@@ -43,7 +43,7 @@
  */
 @RunWith(Parameterized.class)
 public class MatchPredicateStrategyTest {
-    private static final Translator<String,String> translator = GroovyTranslator.of("__");
+    private static final Translator.ScriptTranslator translator = GroovyTranslator.of("__");
 
     @Parameterized.Parameter(value = 0)
     public Traversal.Admin original;
@@ -56,7 +56,7 @@
 
     @Test
     public void doTest() {
-        final String repr = translator.translate(original.getBytecode());
+        final String repr = translator.translate(original.getBytecode()).getScript();
         final TraversalStrategies strategies = new DefaultTraversalStrategies();
         strategies.addStrategies(MatchPredicateStrategy.instance());
         for (final TraversalStrategy strategy : this.otherStrategies) {
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/OrderLimitStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/OrderLimitStrategyTest.java
index 5d615ee..6fb8d31 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/OrderLimitStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/OrderLimitStrategyTest.java
@@ -42,7 +42,7 @@
  */
 @RunWith(Parameterized.class)
 public class OrderLimitStrategyTest {
-    private static final Translator<String,String> translator = GroovyTranslator.of("__");
+    private static final Translator.ScriptTranslator translator = GroovyTranslator.of("__");
 
     @Parameterized.Parameter(value = 0)
     public Traversal.Admin traversal;
@@ -59,7 +59,7 @@
 
     @Test
     public void doTest() {
-        final String repr = translator.translate(traversal.getBytecode());
+        final String repr = translator.translate(traversal.getBytecode()).getScript();
         traversal.asAdmin().setParent(new TraversalVertexProgramStep(EmptyTraversal.instance(), EmptyTraversal.instance())); // trick it
         applyOrderLimitStrategyStrategy(traversal);
         assertEquals(repr, limit, TraversalHelper.getFirstStepOfAssignableClass(OrderGlobalStep.class, traversal.asAdmin()).get().getLimit());
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/PathProcessorStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/PathProcessorStrategyTest.java
index 863f525..489e155 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/PathProcessorStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/PathProcessorStrategyTest.java
@@ -28,7 +28,7 @@
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
-import org.apache.tinkerpop.gremlin.process.traversal.lambda.ElementValueTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.lambda.ValueTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.lambda.IdentityTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
 import org.apache.tinkerpop.gremlin.process.traversal.translator.GroovyTranslator;
@@ -49,7 +49,7 @@
  */
 @RunWith(Parameterized.class)
 public class PathProcessorStrategyTest {
-    private static final Translator<String,String> translator = GroovyTranslator.of("__");
+    private static final Translator.ScriptTranslator translator = GroovyTranslator.of("__");
 
     @Parameterized.Parameter(value = 0)
     public Traversal.Admin original;
@@ -62,7 +62,7 @@
 
     @Test
     public void doTest() {
-        final String repr = translator.translate(original.getBytecode());
+        final String repr = translator.translate(original.getBytecode()).getScript();
         final Traversal.Admin<?, ?> rootTraversal = new DefaultGraphTraversal<>();
         final TraversalParent parent = new TraversalVertexProgramStep(rootTraversal, this.original.asAdmin());
         rootTraversal.addStep(parent.asStep());
@@ -86,20 +86,20 @@
                 {__.select("a"), __.select("a"), Collections.emptyList()},
                 {__.select("a").by(), __.select("a").by(), Collections.emptyList()},
                 {__.select("a").by(__.outE().count()), __.select("a").map(__.outE().count()), Collections.emptyList()},
-                {__.select("a").by("name"), __.select("a").map(new ElementValueTraversal<>("name")), Collections.emptyList()},
+                {__.select("a").by("name"), __.select("a").map(new ValueTraversal<>("name")), Collections.emptyList()},
                 {__.select("a").out(), __.select("a").out(), Collections.emptyList()},
-                {__.select(Pop.all, "a").by(__.values("name")), __.select(Pop.all, "a").by(__.values("name")), TraversalStrategies.GlobalCache.getStrategies(Graph.class).toList()},
+                {__.select(Pop.all, "a").by(__.values("name")), __.select(Pop.all, "a").by("name"), TraversalStrategies.GlobalCache.getStrategies(Graph.class).toList()},
                 {__.select(Pop.last, "a").by(__.values("name")), __.select(Pop.last, "a").map(__.values("name")), TraversalStrategies.GlobalCache.getStrategies(Graph.class).toList()},
                 {__.select(Pop.first, "a").by(__.values("name")), __.select(Pop.first, "a").map(__.values("name")), TraversalStrategies.GlobalCache.getStrategies(Graph.class).toList()},
                 // select("a","b")
                 {__.select("a", "b"), __.select("a", "b"), Collections.emptyList()},
                 {__.select("a", "b").by(), __.select("a", "b").by(), Collections.emptyList()},
                 {__.select("a", "b", "c").by(), __.select("a", "b", "c").by(), Collections.emptyList()},
-                {__.select("a", "b").by().by("age"), __.select("b").map(new ElementValueTraversal<>("age")).as("b").select("a").map(new IdentityTraversal<>()).as("a").select(Pop.last, "a", "b"), TraversalStrategies.GlobalCache.getStrategies(Graph.class).toList()},
-                {__.select("a", "b").by("name").by("age"), __.select("b").map(new ElementValueTraversal<>("age")).as("b").select("a").map(new ElementValueTraversal<>("name")).as("a").select(Pop.last, "a", "b"), Collections.emptyList()},
-                {__.select("a", "b", "c").by("name").by(__.outE().count()), __.select("c").map(new ElementValueTraversal<>("name")).as("c").select("b").map(__.outE().count()).as("b").select("a").map(new ElementValueTraversal<>("name")).as("a").select(Pop.last, "a", "b", "c"), TraversalStrategies.GlobalCache.getStrategies(Graph.class).toList()},
-                {__.select(Pop.first, "a", "b").by("name").by("age"), __.select(Pop.first, "b").map(new ElementValueTraversal<>("age")).as("b").select(Pop.first, "a").map(new ElementValueTraversal<>("name")).as("a").select(Pop.last, "a", "b"), Collections.emptyList()},
-                {__.select(Pop.last, "a", "b").by("name").by("age"), __.select(Pop.last, "b").map(new ElementValueTraversal<>("age")).as("b").select(Pop.last, "a").map(new ElementValueTraversal<>("name")).as("a").select(Pop.last, "a", "b"), TraversalStrategies.GlobalCache.getStrategies(Graph.class).toList()},
+                {__.select("a", "b").by().by("age"), __.select("b").map(new ValueTraversal<>("age")).as("b").select("a").map(new IdentityTraversal<>()).as("a").select(Pop.last, "a", "b"), TraversalStrategies.GlobalCache.getStrategies(Graph.class).toList()},
+                {__.select("a", "b").by("name").by("age"), __.select("b").map(new ValueTraversal<>("age")).as("b").select("a").map(new ValueTraversal<>("name")).as("a").select(Pop.last, "a", "b"), Collections.emptyList()},
+                {__.select("a", "b", "c").by("name").by(__.outE().count()), __.select("c").map(new ValueTraversal<>("name")).as("c").select("b").map(__.outE().count()).as("b").select("a").map(new ValueTraversal<>("name")).as("a").select(Pop.last, "a", "b", "c"), TraversalStrategies.GlobalCache.getStrategies(Graph.class).toList()},
+                {__.select(Pop.first, "a", "b").by("name").by("age"), __.select(Pop.first, "b").map(new ValueTraversal<>("age")).as("b").select(Pop.first, "a").map(new ValueTraversal<>("name")).as("a").select(Pop.last, "a", "b"), Collections.emptyList()},
+                {__.select(Pop.last, "a", "b").by("name").by("age"), __.select(Pop.last, "b").map(new ValueTraversal<>("age")).as("b").select(Pop.last, "a").map(new ValueTraversal<>("name")).as("a").select(Pop.last, "a", "b"), TraversalStrategies.GlobalCache.getStrategies(Graph.class).toList()},
                 {__.select(Pop.all, "a", "b").by("name").by("age"), __.select(Pop.all, "a", "b").by("name").by("age"), Collections.emptyList()},
                 {__.select(Pop.mixed, "a", "b").by("name").by("age"), __.select(Pop.mixed, "a", "b").by("name").by("age"), Collections.emptyList()},
                 // where(as("a")...)
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/PathRetractionStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/PathRetractionStrategyTest.java
index d6130e9..80ee82d 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/PathRetractionStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/PathRetractionStrategyTest.java
@@ -68,7 +68,7 @@
  */
 @RunWith(Parameterized.class)
 public class PathRetractionStrategyTest {
-    private static final Translator<String,String> translator = GroovyTranslator.of("__");
+    private static final Translator.ScriptTranslator translator = GroovyTranslator.of("__");
 
     /**
      * Always need LazyBarrierStrategy because it will trigger barrier() additions in PathRetractionStrategy.
@@ -92,7 +92,7 @@
 
     @Test
     public void doTest() {
-        final String repr = translator.translate(original.getBytecode());
+        final String repr = translator.translate(original.getBytecode()).getScript();
         for (final TraversalStrategies currentStrategies : this.strategies) {
             final Traversal.Admin<?, ?> currentTraversal = this.original.clone();
             currentTraversal.setStrategies(currentStrategies);
@@ -104,7 +104,7 @@
     }
 
     private List<Object> getKeepLabels(final Traversal.Admin<?, ?> traversal) {
-        List<Object> keepLabels = new ArrayList<>();
+        final List<Object> keepLabels = new ArrayList<>();
         for (Step step : traversal.getSteps()) {
             if (step instanceof PathProcessor) {
                 final Set<String> keepers = ((PathProcessor) step).getKeepLabels();
@@ -145,11 +145,26 @@
                 {__.V().as("a").out().where(neq("a")).out().select("a"), "[[a], []]", null},
                 {__.V().as("a").out().as("b").where(neq("a")).out().select("a", "b").out().select("b"), "[[a, b], [b], []]", null},
                 {__.V().match(as("a").out().as("b")), "[[a, b]]", null},
-                {__.V().match(as("a").out().as("b")).select("a"), "[[a], []]", null},
+                {__.V().match(as("a").out().as("b")).dedup(), "[[a, b], []]", null},
+                {__.V().match(as("a").out().as("b")).identity().dedup().identity(), "[[a, b], []]", null},
+                // MatchPredicateStrategy folds the dedup("a") into the match() so the step labels don't assert
+                // cleanly here given limitations of the suite that don't let us ignore a particular run. so the
+                // following will assert with "[[a, b], []]" but also "[[a, b]]" when MatchPredicateStrategy does
+                // its thing:
+                // {__.V().match(as("a").out("knows").as("b")).dedup("a"), "[[a, b], []]", null},
+                // would be nice if we could better detect dedup("a") with some form of look-ahead. note that
+                // MatchPredicateStrategy misses this pattern because of identity()
+                {__.V().match(as("a").out().as("b")).identity().dedup("a").identity(), "[[a, b], []]", null},
+                {__.V().match(as("a").out().as("b")).identity(), "[[a, b]]", null},
+                {__.V().match(as("a").out().as("b")).unfold(), "[[a, b]]", null},
+                {__.V().match(as("a").out().as("b")).unfold().identity(), "[[a, b]]", null},
+                // would be nice if we could better detect select("a") with some form of look-ahead
+                {__.V().match(as("a").out().as("b")).select("a"), "[[a, b], []]", null},
+                // would be nice to detect and retract "a" and "c" earlier
                 {__.V().out().out().match(
                         as("a").in("created").as("b"),
                         as("b").in("knows").as("c")).select("c").out("created").where(neq("a")).values("name"),
-                        "[[a, c], [a], []]", null},
+                        "[[a, b, c], [a], []]", null},
                 {__.V().as("a").out().select("a").path(), PATH_RETRACTION_STRATEGY_DISABLED, null},
                 {__.V().as("a").out().select("a").map(t -> t.path().get("a")), PATH_RETRACTION_STRATEGY_DISABLED, null}, // lambda introspection is not possible
                 {__.V().as("a").out().select("a").subgraph("b"), "[[]]", null},
@@ -164,15 +179,17 @@
                         "[[[a, b]], [b], []]", null},
                 {__.outE().inV().group().by(__.inE().outV().groupCount().by(__.both().count().is(P.gt(2)))), "[]", null},
                 {__.V().as("a").repeat(out().where(neq("a"))).emit().select("a").values("test"), "[[[a]], []]", null},
-                // given the way this test harness is structured, I have to manual test for RepeatUnrollStrategy (and it works) TODO: add more test parameters
+                // given the way this test harness is structured, I have to manual test for RepeatUnrollStrategy (and it works)
                 // {__.V().as("a").repeat(__.out().where(neq("a"))).times(3).select("a").values("test"), Arrays.asList(Collections.singleton("a"), Collections.singleton("a"), Collections.singleton("a"), Collections.emptySet())}
                 {__.V().as("a").out().as("b").select("a").out().out(), "[[]]", __.V().as("a").out().as("b").select("a").barrier(PathRetractionStrategy.MAX_BARRIER_SIZE).out().barrier(LazyBarrierStrategy.MAX_BARRIER_SIZE).out()},
                 {__.V().as("a").out().as("b").select("a").count(), "[[]]", __.V().as("a").out().as("b").select("a").count()},
                 {__.V().as("a").out().as("b").select("a").barrier().count(), "[[]]", __.V().as("a").out().as("b").select("a").barrier().count()},
                 {__.V().as("a").out().as("b").dedup("a", "b").out(), "[[]]", __.V().as("a").out().as("b").dedup("a", "b").out()},
                 {__.V().as("a").out().as("b").match(as("a").out().as("b")), "[[a, b]]", __.V().as("a").out().as("b").match(as("a").out().as("b"))},
-                {__.V().as("a").out().as("b").match(as("a").out().as("b")).select("a"), "[[a], []]", __.V().as("a").out().as("b").match(as("a").out().as("b")).select("a")},
-                {__.V().as("a").out().as("b").match(as("a").out().as("b")).select("a").out().dedup("a"), "[[a], [a], []]", __.V().as("a").out().as("b").match(as("a").out().as("b")).select("a").barrier(PathRetractionStrategy.MAX_BARRIER_SIZE).out().dedup("a")},
+                // would be nice if we could better detect select("a") with some form of look-ahead
+                {__.V().as("a").out().as("b").match(as("a").out().as("b")).select("a"), "[[a, b], []]", __.V().as("a").out().as("b").match(as("a").out().as("b")).select("a")},
+                // would be nice if we could better detect select("a")/dedup("a") with some form of look-ahead
+                {__.V().as("a").out().as("b").match(as("a").out().as("b")).select("a").out().dedup("a"), "[[a, b], [a], []]", __.V().as("a").out().as("b").match(as("a").out().as("b")).select("a").barrier(PathRetractionStrategy.MAX_BARRIER_SIZE).out().dedup("a")},
                 {__.V().as("a").out().as("b").where(P.gt("a")).out().out(), "[[]]", __.V().as("a").out().as("b").where(P.gt("a")).barrier(PathRetractionStrategy.MAX_BARRIER_SIZE).out().barrier(LazyBarrierStrategy.MAX_BARRIER_SIZE).out()},
                 {__.V().as("a").out().as("b").where(P.gt("a")).count(), "[[]]", __.V().as("a").out().as("b").where(P.gt("a")).count()},
                 {__.V().as("a").out().as("b").select("a").as("c").where(P.gt("b")).out(), "[[b], []]", __.V().as("a").out().as("b").select("a").as("c").barrier(PathRetractionStrategy.MAX_BARRIER_SIZE).where(P.gt("b")).barrier(PathRetractionStrategy.MAX_BARRIER_SIZE).out()},
@@ -187,9 +204,8 @@
                         local(as("c").out().as("d", "e").select("c", "e").out().select("c")).
                         out().select("c"),
                         "[[b, c, e], [c, e], [[c], [c]], []]", null},
-                // TODO: same as above but note how path() makes things react
-//                {__.V().as("a").out().as("b").select("a").select("b").path().local(as("c").out().as("d", "e").select("c", "e").out().select("c")).out().select("c"),
-//                        "[[[c, e], [c, e]]]", null},
+                {__.V().as("a").out().as("b").select("a").select("b").path().local(as("c").out().as("d", "e").select("c", "e").out().select("c")).out().select("c"),
+                        PATH_RETRACTION_STRATEGY_DISABLED, null},
                 {__.V().as("a").out().as("b").select("a").select("b").repeat(out().as("c").select("b", "c").out().select("c")).out().select("c").out().select("b"),
                         "[[b, c], [b, c], [[b, c], [b, c]], [b], []]", null},
                 {__.V().as("a").out().as("b").select("a").select("b").repeat(out().as("c").select("b")).out().select("c").out().select("b"),
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RepeatUnrollStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RepeatUnrollStrategyTest.java
index 5990ae9..9cd20c4 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RepeatUnrollStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RepeatUnrollStrategyTest.java
@@ -48,7 +48,7 @@
  */
 @RunWith(Parameterized.class)
 public class RepeatUnrollStrategyTest {
-    private static final Translator<String,String> translator = GroovyTranslator.of("__");
+    private static final Translator.ScriptTranslator translator = GroovyTranslator.of("__");
 
     @Parameterized.Parameter(value = 0)
     public Traversal.Admin<?,?> original;
@@ -61,7 +61,7 @@
 
     @Test
     public void doTest() {
-        final String repr = translator.translate(original.getBytecode());
+        final String repr = translator.translate(original.getBytecode()).getScript();
         final TraversalStrategies strategiesWithLazy = new DefaultTraversalStrategies();
         strategiesWithLazy.addStrategies(RepeatUnrollStrategy.instance());
         Traversal.Admin<?, ?> clonedOriginal = this.original.clone();
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ComputerVerificationStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ComputerVerificationStrategyTest.java
index ba3ab95..3d80c2f 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ComputerVerificationStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ComputerVerificationStrategyTest.java
@@ -45,7 +45,7 @@
  */
 @RunWith(Parameterized.class)
 public class ComputerVerificationStrategyTest {
-    private static final Translator<String,String> translator = GroovyTranslator.of("__");
+    private static final Translator.ScriptTranslator translator = GroovyTranslator.of("__");
 
     @Parameterized.Parameters(name = "{0}")
     public static Iterable<Object[]> data() {
@@ -70,7 +70,7 @@
 
     @Test
     public void shouldBeVerifiedIllegal() {
-        final String repr = translator.translate(traversal.getBytecode());
+        final String repr = translator.translate(traversal.getBytecode()).getScript();
 
         final TraversalStrategies strategies = new DefaultTraversalStrategies();
         strategies.addStrategies(ComputerVerificationStrategy.instance());
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/EdgeLabelVerificationStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/EdgeLabelVerificationStrategyTest.java
index aa8ce0a..1b869a4 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/EdgeLabelVerificationStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/EdgeLabelVerificationStrategyTest.java
@@ -49,7 +49,7 @@
  */
 @RunWith(Parameterized.class)
 public class EdgeLabelVerificationStrategyTest {
-    private static final Translator<String,String> translator = GroovyTranslator.of("__");
+    private static final Translator.ScriptTranslator translator = GroovyTranslator.of("__");
 
     private final static Predicate<String> MSG_PREDICATE = Pattern.compile(
             "^The provided traversal contains a vertex step without any specified edge label: VertexStep.*")
@@ -97,7 +97,7 @@
 
     @Test
     public void shouldIgnore() {
-        final String repr = translator.translate(traversal.getBytecode());
+        final String repr = translator.translate(traversal.getBytecode()).getScript();
         final TraversalStrategies strategies = new DefaultTraversalStrategies();
         strategies.addStrategies(EdgeLabelVerificationStrategy.build().create());
         final Traversal traversal = this.traversal.asAdmin().clone();
@@ -108,7 +108,7 @@
 
     @Test
     public void shouldOnlyThrow() {
-        final String repr = translator.translate(traversal.getBytecode());
+        final String repr = translator.translate(traversal.getBytecode()).getScript();
         final TraversalStrategies strategies = new DefaultTraversalStrategies();
         strategies.addStrategies(EdgeLabelVerificationStrategy.build().throwException().create());
         final Traversal traversal = this.traversal.asAdmin().clone();
@@ -128,7 +128,7 @@
 
     @Test
     public void shouldOnlyLog() {
-        final String repr = translator.translate(traversal.getBytecode());
+        final String repr = translator.translate(traversal.getBytecode()).getScript();
         final TraversalStrategies strategies = new DefaultTraversalStrategies();
         strategies.addStrategies(EdgeLabelVerificationStrategy.build().logWarning().create());
         final Traversal traversal = this.traversal.asAdmin().clone();
@@ -142,7 +142,7 @@
 
     @Test
     public void shouldThrowAndLog() {
-        final String repr = translator.translate(traversal.getBytecode());
+        final String repr = translator.translate(traversal.getBytecode()).getScript();
         final TraversalStrategies strategies = new DefaultTraversalStrategies();
         strategies.addStrategies(EdgeLabelVerificationStrategy.build().throwException().logWarning().create());
         final Traversal traversal = this.traversal.asAdmin().clone();
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/LambdaRestrictionStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/LambdaRestrictionStrategyTest.java
index 6618acc..ef2b960 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/LambdaRestrictionStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/LambdaRestrictionStrategyTest.java
@@ -48,7 +48,7 @@
  */
 @RunWith(Parameterized.class)
 public class LambdaRestrictionStrategyTest {
-    private static final Translator<String,String> translator = GroovyTranslator.of("__");
+    private static final Translator.ScriptTranslator translator = GroovyTranslator.of("__");
 
     @Parameterized.Parameters(name = "{0}")
     public static Iterable<Object[]> data() {
@@ -87,7 +87,7 @@
 
     @Test
     public void shouldBeVerifiedIllegal() {
-        final String repr = translator.translate(traversal.getBytecode());
+        final String repr = translator.translate(traversal.getBytecode()).getScript();
         final TraversalStrategies strategies = new DefaultTraversalStrategies();
         strategies.addStrategies(ProfileStrategy.instance());
         strategies.addStrategies(LambdaRestrictionStrategy.instance());
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ReadOnlyStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ReadOnlyStrategyTest.java
index 8df21cb..7984630 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ReadOnlyStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ReadOnlyStrategyTest.java
@@ -39,7 +39,7 @@
  */
 @RunWith(Parameterized.class)
 public class ReadOnlyStrategyTest {
-    private static final Translator<String,String> translator = GroovyTranslator.of("__");
+    private static final Translator.ScriptTranslator translator = GroovyTranslator.of("__");
 
     @Parameterized.Parameters(name = "{0}")
     public static Iterable<Object[]> data() {
@@ -61,7 +61,7 @@
 
     @Test
     public void shouldBeVerifiedIllegal() {
-        final String repr = translator.translate(traversal.getBytecode());
+        final String repr = translator.translate(traversal.getBytecode()).getScript();
         try {
             ReadOnlyStrategy.instance().apply(this.traversal.asAdmin());
             fail("The strategy should have found a mutating step: " + repr);
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ReservedKeysVerificationStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ReservedKeysVerificationStrategyTest.java
index db7f47b..f037e39 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ReservedKeysVerificationStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ReservedKeysVerificationStrategyTest.java
@@ -52,7 +52,7 @@
  */
 @RunWith(Parameterized.class)
 public class ReservedKeysVerificationStrategyTest {
-    private static final Translator<String,String> translator = GroovyTranslator.of("__");
+    private static final Translator.ScriptTranslator translator = GroovyTranslator.of("__");
 
     private final static Predicate<String> MSG_PREDICATE = Pattern.compile(
             ".*that is setting a property key to a reserved word.*")
@@ -99,7 +99,7 @@
 
     @Test
     public void shouldIgnore() {
-        final String repr = translator.translate(traversal.getBytecode());
+        final String repr = translator.translate(traversal.getBytecode()).getScript();
         final TraversalStrategies strategies = new DefaultTraversalStrategies();
         strategies.addStrategies(ReservedKeysVerificationStrategy.build().create());
         final Traversal traversal = this.traversal.asAdmin().clone();
@@ -110,7 +110,7 @@
 
     @Test
     public void shouldOnlyThrow() {
-        final String repr = translator.translate(traversal.getBytecode());
+        final String repr = translator.translate(traversal.getBytecode()).getScript();
         final TraversalStrategies strategies = new DefaultTraversalStrategies();
         final ReservedKeysVerificationStrategy.Builder builder = ReservedKeysVerificationStrategy.build().throwException();
         if (repr.equals("__.addV().property(\"x\",\"xyz\",\"not-allowed\",\"xxx\")"))
@@ -133,7 +133,7 @@
 
     @Test
     public void shouldOnlyLog() {
-        final String repr = translator.translate(traversal.getBytecode());
+        final String repr = translator.translate(traversal.getBytecode()).getScript();
         final TraversalStrategies strategies = new DefaultTraversalStrategies();
         final ReservedKeysVerificationStrategy.Builder builder = ReservedKeysVerificationStrategy.build().logWarning();
         if (repr.equals("__.addV().property(\"x\",\"xyz\",\"not-allowed\",\"xxx\")"))
@@ -150,7 +150,7 @@
 
     @Test
     public void shouldThrowAndLog() {
-        final String repr = translator.translate(traversal.getBytecode());
+        final String repr = translator.translate(traversal.getBytecode()).getScript();
         final TraversalStrategies strategies = new DefaultTraversalStrategies();
         final ReservedKeysVerificationStrategy.Builder builder = ReservedKeysVerificationStrategy.build().
                 throwException().logWarning();
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/StandardVerificationStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/StandardVerificationStrategyTest.java
index f47d7dc..084b795 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/StandardVerificationStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/StandardVerificationStrategyTest.java
@@ -46,7 +46,7 @@
  */
 @RunWith(Parameterized.class)
 public class StandardVerificationStrategyTest {
-    private static final Translator<String,String> translator = GroovyTranslator.of("__");
+    private static final Translator.ScriptTranslator translator = GroovyTranslator.of("__");
 
     @Parameterized.Parameters(name = "{0}")
     public static Iterable<Object[]> data() throws Exception {
@@ -71,7 +71,7 @@
 
     @Test
     public void shouldBeVerified() {
-        final String repr = translator.translate(traversal.getBytecode());
+        final String repr = translator.translate(traversal.getBytecode()).getScript();
         final Traversal copy = copyAndConfigureTraversal(traversal);
 
         if (legalTraversal) {
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslatorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslatorTest.java
new file mode 100644
index 0000000..a1ec5cb
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslatorTest.java
@@ -0,0 +1,220 @@
+/*
+ *  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.translator;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Order;
+import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.Pop;
+import org.apache.tinkerpop.gremlin.process.traversal.Scope;
+import org.apache.tinkerpop.gremlin.process.traversal.Translator;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy;
+import org.apache.tinkerpop.gremlin.structure.Column;
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.T;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedEdge;
+import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex;
+import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.UUID;
+
+import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal;
+import static org.apache.tinkerpop.gremlin.process.traversal.Order.asc;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.hasLabel;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class DotNetTranslatorTest {
+    private static final GraphTraversalSource g = traversal().withEmbedded(EmptyGraph.instance());
+    private static final Translator.ScriptTranslator translator = DotNetTranslator.of("g");
+
+    @Test
+    public void shouldTranslateStrategies() throws Exception {
+        assertEquals("g.WithStrategies(new ReadOnlyStrategy()," +
+                        "new SubgraphStrategy(checkAdjacentVertices: false, vertices: __.HasLabel(\"person\"))).V().Has(\"name\")",
+                translator.translate(g.withStrategies(ReadOnlyStrategy.instance(),
+                        SubgraphStrategy.build().checkAdjacentVertices(false).vertices(hasLabel("person")).create()).
+                        V().has("name").asAdmin().getBytecode()).getScript());
+    }
+
+    @Test
+    public void shouldTranslateMaps() {
+        final String script = translator.translate(g.V().id().is(new LinkedHashMap<Object,Object>() {{
+            put(3, "32");
+            put(Arrays.asList(1, 2, 3.1d), 4);
+        }}).asAdmin().getBytecode()).getScript();
+        assertEquals("g.V().Id().Is(new Dictionary<object,object> {{3, \"32\"}, {new List<object> {1, 2, 3.1}, 4}})", script);
+    }
+
+    @Test
+    public void shouldTranslateValues() {
+        final String script = translator.translate(g.V().values("name").asAdmin().getBytecode()).getScript();
+        assertEquals("g.V().Values<object>(\"name\")", script);
+    }
+
+    @Test
+    public void shouldTranslateValue() {
+        final String script = translator.translate(g.V().properties().order().by(T.value, asc).value().asAdmin().getBytecode()).getScript();
+        assertEquals("g.V().Properties<object>().Order().By(T.Value,Order.Asc).Value<object>()", script);
+    }
+
+    @Test
+    public void shouldTranslateInject() {
+        final String script = translator.translate(g.inject(10,20,null,20,10,10).asAdmin().getBytecode()).getScript();
+        assertEquals("g.Inject<object>(10,20,null,20,10,10)", script);
+    }
+
+    @Test
+    public void shouldTranslateGroup() {
+        final String script = translator.translate(g.V().group("x").group().by("name").asAdmin().getBytecode()).getScript();
+        assertEquals("g.V().Group(\"x\").Group<object,object>().By(\"name\")", script);
+    }
+
+    @Test
+    public void shouldTranslateGroupCount() {
+        final String script = translator.translate(g.V().groupCount("x").groupCount().by("name").asAdmin().getBytecode()).getScript();
+        assertEquals("g.V().GroupCount(\"x\").GroupCount<object>().By(\"name\")", script);
+    }
+
+    @Test
+    public void shouldTranslateDate() {
+        final Calendar c = Calendar.getInstance();
+        c.set(1975, Calendar.SEPTEMBER, 7);
+        final Date d = c.getTime();
+        assertTranslation(String.format("DateTimeOffset.FromUnixTimeMilliseconds(%s)", d.getTime()), d);
+    }
+
+    @Test
+    public void shouldTranslateUuid() {
+        final UUID uuid = UUID.fromString("ffffffff-fd49-1e4b-0000-00000d4b8a1d");
+        assertTranslation(String.format("new Guid(\"%s\")", uuid), uuid);
+    }
+
+    @Test
+    public void shouldTranslateP() {
+        assertTranslation("P.Gt(1).And(P.Gt(2)).And(P.Gt(3))", P.gt(1).and(P.gt(2)).and(P.gt(3)));
+    }
+
+    @Test
+    public void shouldTranslateColumn() {
+        assertTranslation("Column.Keys", Column.keys);
+    }
+
+    @Test
+    public void shouldTranslateDirection() {
+        assertTranslation("Direction.Both", Direction.BOTH);
+    }
+
+    @Test
+    public void shouldTranslateOrder() {
+        assertTranslation("Order.Desc", Order.desc);
+    }
+
+    @Test
+    public void shouldTranslatePop() {
+        assertTranslation("Pop.Last", Pop.last);
+    }
+
+    @Test
+    public void shouldTranslateScope() {
+        assertTranslation("Scope.Local", Scope.local);
+    }
+
+    @Test
+    public void shouldHaveValidToString() {
+        assertEquals("translator[h:gremlin-dotnet]", DotNetTranslator.of("h").toString());
+    }
+
+    @Test
+    public void shouldEscapeStrings() {
+        final String script = translator.translate(g.addV("customer")
+                .property("customer_id", 501L)
+                .property("name", "Foo\u0020Bar")
+                .property("age", 25)
+                .property("special", "`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?")
+                .asAdmin().getBytecode()).getScript();
+
+        assertEquals("g.AddV(\"customer\")" +
+                        ".Property(\"customer_id\",501)" +
+                        ".Property(\"name\",\"Foo Bar\")" +
+                        ".Property(\"age\",25)" +
+                        ".Property(\"special\",\"`~!@#$%^&*()-_=+[{]}\\\\|;:'\\\",<.>/?\")",
+                script);
+    }
+
+    @Test
+    public void shouldTranslateVertexAndEdge() {
+        final Object id1 = "customer:10:foo\u0020bar\u0020\u0024100#90"; // customer:10:foo bar $100#90
+        final Vertex vertex1 = DetachedVertex.build().setLabel("customer").setId(id1)
+                .create();
+        final String script1 = translator.translate(g.inject(vertex1).asAdmin().getBytecode()).getScript();
+        assertEquals("g.Inject(new Vertex(" +
+                        "\"customer:10:foo bar $100#90\", " +
+                        "\"customer\"))",
+                script1);
+
+        final Object id2 = "user:20:foo\\u0020bar\\u005c\\u0022mr\\u005c\\u0022\\u00241000#50"; // user:20:foo\u0020bar\u005c\u0022mr\u005c\u0022\u00241000#50
+        final Vertex vertex2 = DetachedVertex.build().setLabel("user").setId(id2)
+                .create();
+        final String script2 = translator.translate(g.inject(vertex2).asAdmin().getBytecode()).getScript();
+        assertEquals("g.Inject(new Vertex(" +
+                        "\"user:20:foo\\\\u0020bar\\\\u005c\\\\u0022mr\\\\u005c\\\\u0022\\\\u00241000#50\", " +
+                        "\"user\"))",
+                script2);
+
+        final Object id3 = "knows:30:foo\u0020bar\u0020\u0024100:\\u0020\\u0024500#70";
+        final Edge edge = DetachedEdge.build().setLabel("knows").setId(id3)
+                .setOutV((DetachedVertex) vertex1)
+                .setInV((DetachedVertex) vertex2)
+                .create();
+        final String script3 = translator.translate(g.inject(edge).asAdmin().getBytecode()).getScript();
+        assertEquals("g.Inject(" +
+                        "new Edge(\"knows:30:foo bar $100:\\\\u0020\\\\u0024500#70\", " +
+                        "new Vertex(\"customer:10:foo bar $100#90\", \"customer\"), " +
+                        "\"knows\", " +
+                        "new Vertex(\"user:20:foo\\\\u0020bar\\\\u005c\\\\u0022mr\\\\u005c\\\\u0022\\\\u00241000#50\", \"user\")))",
+                script3);
+
+        final String script4 = translator.translate(
+                g.addE("knows").from(vertex1).to(vertex2).property("when", "2018/09/21")
+                        .asAdmin().getBytecode()).getScript();
+        assertEquals("g.AddE(\"knows\")" +
+                        ".From(new Vertex(\"customer:10:foo bar $100#90\", \"customer\"))" +
+                        ".To(new Vertex(\"user:20:foo\\\\u0020bar\\\\u005c\\\\u0022mr\\\\u005c\\\\u0022\\\\u00241000#50\", \"user\"))" +
+                        ".Property(\"when\",\"2018/09/21\")",
+                script4);
+    }
+
+    private void assertTranslation(final String expectedTranslation, final Object... objs) {
+        final String script = translator.translate(g.inject(objs).asAdmin().getBytecode()).getScript();
+        assertEquals(String.format("g.Inject(%s)", expectedTranslation), script);
+    }
+}
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslatorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslatorTest.java
index a466c5b..82d679d 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslatorTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslatorTest.java
@@ -19,10 +19,10 @@
 
 package org.apache.tinkerpop.gremlin.process.traversal.translator;
 
-import org.apache.tinkerpop.gremlin.jsr223.TranslatorCustomizer;
 import org.apache.tinkerpop.gremlin.process.traversal.Order;
 import org.apache.tinkerpop.gremlin.process.traversal.Pop;
 import org.apache.tinkerpop.gremlin.process.traversal.Scope;
+import org.apache.tinkerpop.gremlin.process.traversal.Script;
 import org.apache.tinkerpop.gremlin.process.traversal.Translator;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
@@ -66,25 +66,25 @@
         assertEquals("g.withStrategies(ReadOnlyStrategy,new SubgraphStrategy(checkAdjacentVertices: false, vertices: __.hasLabel(\"person\"))).V().has(\"name\")",
                 translator.translate(g.withStrategies(ReadOnlyStrategy.instance(),
                         SubgraphStrategy.build().checkAdjacentVertices(false).vertices(hasLabel("person")).create()).
-                        V().has("name")));
+                        V().has("name")).getScript());
     }
 
     @Test
     public void shouldTranslateConfusingSacks() {
         final Traversal<Vertex,Double> tConstantUnary = g.withSack(1.0, Lambda.unaryOperator("it + 1")).V().sack();
-        final String scriptConstantUnary = translator.translate(tConstantUnary);
+        final String scriptConstantUnary = translator.translate(tConstantUnary).getScript();
         assertEquals("g.withSack(1.0d,{it + 1}).V().sack()", scriptConstantUnary);
 
         final Traversal<Vertex,Double> tSupplierUnary = g.withSack(Lambda.supplier("1.0d"), Lambda.<Double>unaryOperator("it + 1")).V().sack();
-        final String scriptSupplierUnary = translator.translate(tSupplierUnary);
+        final String scriptSupplierUnary = translator.translate(tSupplierUnary).getScript();
         assertEquals("g.withSack({1.0d},{it + 1}).V().sack()", scriptSupplierUnary);
 
         final Traversal<Vertex,Double> tConstantBinary = g.withSack(1.0, Lambda.binaryOperator("x,y -> x + y + 1")).V().sack();
-        final String scriptConstantBinary = translator.translate(tConstantBinary);
+        final String scriptConstantBinary = translator.translate(tConstantBinary).getScript();
         assertEquals("g.withSack(1.0d,{x,y -> x + y + 1}).V().sack()", scriptConstantBinary);
 
         final Traversal<Vertex,Double> tSupplierBinary = g.withSack(Lambda.supplier("1.0d"), Lambda.<Double>binaryOperator("x,y -> x + y + 1")).V().sack();
-        final String scriptSupplierBinary = translator.translate(tSupplierBinary);
+        final String scriptSupplierBinary = translator.translate(tSupplierBinary).getScript();
         assertEquals("g.withSack({1.0d},{x,y -> x + y + 1}).V().sack()", scriptSupplierBinary);
     }
 
@@ -100,7 +100,7 @@
                 .sack(Lambda.biFunction("{ a,b -> a + b }"))
                 .asAdmin();
 
-        final String script = translator.translate(t.getBytecode());
+        final String script = translator.translate(t.getBytecode()).getScript();
         assertEquals(   "g.withSideEffect(\"lengthSum\",(int) 0).withSack((int) 1)" +
                         ".V()" +
                         ".filter({it.get().label().equals('person')})" +
@@ -117,14 +117,14 @@
         final String script = translator.translate(g.V().id().is(new LinkedHashMap<Object,Object>() {{
             put(3, "32");
             put(Arrays.asList(1, 2, 3.1d), 4);
-        }}));
+        }})).getScript();
         assertEquals("g.V().id().is([((int) 3):(\"32\"),([(int) 1, (int) 2, 3.1d]):((int) 4)])", script);
     }
 
     @Test
     public void shouldTranslateEmptyMaps() {
         final Function identity = new Lambda.OneArgLambda("it.get()", "gremlin-groovy");
-        final String script = translator.translate(g.inject(Collections.emptyMap()).map(identity));
+        final String script = translator.translate(g.inject(Collections.emptyMap()).map(identity)).getScript();
         assertEquals("g.inject([]).map({it.get()})", script);
     }
 
@@ -162,7 +162,7 @@
 
     @Test
     public void shouldTranslateOrder() {
-        assertTranslation("Order.decr", Order.decr);
+        assertTranslation("Order.desc", Order.desc);
     }
 
     @Test
@@ -181,12 +181,12 @@
 
         // without type translation we get uglinesss
         final String scriptBad = translator.
-                translate(g.inject(notSillyEnough));
+                translate(g.inject(notSillyEnough)).getScript();
         assertEquals(String.format("g.inject(%s)", "not silly enough:100"), scriptBad);
 
         // with type translation we get valid gremlin
-        final String scriptGood = GroovyTranslator.of("g", new SillyClassTranslator()).
-                translate(g.inject(notSillyEnough));
+        final String scriptGood = GroovyTranslator.of("g", new SillyClassTranslator(false)).
+                translate(g.inject(notSillyEnough)).getScript();
         assertEquals(String.format("g.inject(org.apache.tinkerpop.gremlin.groovy.jsr223.GroovyTranslatorTest.SillyClass.from('%s', (int) %s))", notSillyEnough.getX(), notSillyEnough.getY()), scriptGood);
     }
 
@@ -202,7 +202,7 @@
                 .property("name", "Foo\u0020Bar")
                 .property("age", 25)
                 .property("special", "`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?")
-                );
+                ).getScript();
 
         assertEquals("g.addV(\"customer\")" +
                         ".property(\"customer_id\",501L)" +
@@ -217,7 +217,7 @@
         final Object id1 = "customer:10:foo\u0020bar\u0020\u0024100#90"; // customer:10:foo bar $100#90
         final Vertex vertex1 = DetachedVertex.build().setLabel("customer").setId(id1)
                 .create();
-        final String script1 = translator.translate(g.inject(vertex1));
+        final String script1 = translator.translate(g.inject(vertex1)).getScript();
         assertEquals("g.inject(new ReferenceVertex(" +
                         "\"customer:10:foo bar \\$100#90\"," +
                         "\"customer\"))",
@@ -226,7 +226,7 @@
         final Object id2 = "user:20:foo\\u0020bar\\u005c\\u0022mr\\u005c\\u0022\\u00241000#50"; // user:20:foo\u0020bar\u005c\u0022mr\u005c\u0022\u00241000#50
         final Vertex vertex2 = DetachedVertex.build().setLabel("user").setId(id2)
                 .create();
-        final String script2 = translator.translate(g.inject(vertex2));
+        final String script2 = translator.translate(g.inject(vertex2)).getScript();
         assertEquals("g.inject(new ReferenceVertex(" +
                         "\"user:20:foo\\\\u0020bar\\\\u005c\\\\u0022mr\\\\u005c\\\\u0022\\\\u00241000#50\"," +
                         "\"user\"))",
@@ -237,7 +237,7 @@
                 .setOutV((DetachedVertex) vertex1)
                 .setInV((DetachedVertex) vertex2)
                 .create();
-        final String script3 = translator.translate(g.inject(edge));
+        final String script3 = translator.translate(g.inject(edge)).getScript();
         assertEquals("g.inject(new ReferenceEdge(" +
                         "\"knows:30:foo bar \\$100:\\\\u0020\\\\u0024500#70\"," +
                         "\"knows\"," +
@@ -247,7 +247,7 @@
 
         final String script4 = translator.translate(
                 g.addE("knows").from(vertex1).to(vertex2).property("when", "2018/09/21")
-                        );
+                        ).getScript();
         assertEquals("g.addE(\"knows\")" +
                         ".from(new ReferenceVertex(\"customer:10:foo bar \\$100#90\",\"customer\"))" +
                         ".to(new ReferenceVertex(\"user:20:foo\\\\u0020bar\\\\u005c\\\\u0022mr\\\\u005c\\\\u0022\\\\u00241000#50\",\"user\"))" +
@@ -256,7 +256,7 @@
     }
 
     private void assertTranslation(final String expectedTranslation, final Object... objs) {
-        final String script = translator.translate(g.inject(objs));
+        final String script = translator.translate(g.inject(objs)).getScript();
         assertEquals(String.format("g.inject(%s)", expectedTranslation), script);
     }
 
@@ -290,21 +290,18 @@
 
     public static class SillyClassTranslator extends GroovyTranslator.DefaultTypeTranslator {
 
-        @Override
-        protected String convertToString(final Object object) {
-            if (object instanceof SillyClass)
-                return String.format("org.apache.tinkerpop.gremlin.groovy.jsr223.GroovyTranslatorTest.SillyClass.from('%s', (int) %s)",
-                        ((SillyClass) object).getX(), ((SillyClass) object).getY());
-            else
-                return super.convertToString(object);
+        public SillyClassTranslator(final boolean withParameters) {
+            super(withParameters);
         }
-    }
-
-    public static class SillyClassTranslatorCustomizer implements TranslatorCustomizer {
 
         @Override
-        public Translator.ScriptTranslator.TypeTranslator createTypeTranslator() {
-            return new SillyClassTranslator();
+        protected Script convertToScript(final Object object) {
+            if (object instanceof SillyClass) {
+                return script.append(String.format("org.apache.tinkerpop.gremlin.groovy.jsr223.GroovyTranslatorTest.SillyClass.from('%s', (int) %s)",
+                        ((SillyClass) object).getX(), ((SillyClass) object).getY()));
+            } else {
+                return super.convertToScript(object);
+            }
         }
     }
 }
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslatorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslatorTest.java
new file mode 100644
index 0000000..5990418
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslatorTest.java
@@ -0,0 +1,182 @@
+/*
+ *  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.translator;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Order;
+import org.apache.tinkerpop.gremlin.process.traversal.Pop;
+import org.apache.tinkerpop.gremlin.process.traversal.Scope;
+import org.apache.tinkerpop.gremlin.process.traversal.Translator;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy;
+import org.apache.tinkerpop.gremlin.structure.Column;
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedEdge;
+import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex;
+import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.UUID;
+
+import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.hasLabel;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class JavascriptTranslatorTest {
+    private static final GraphTraversalSource g = traversal().withEmbedded(EmptyGraph.instance());
+    private static final Translator.ScriptTranslator translator = JavascriptTranslator.of("g");
+
+    @Test
+    public void shouldTranslateStrategies() throws Exception {
+        assertEquals("g.withStrategies(new ReadOnlyStrategy()," +
+                        "new SubgraphStrategy(new Map([[\"checkAdjacentVertices\",false],[\"vertices\",__.hasLabel(\"person\")]]))).V().has(\"name\")",
+                translator.translate(g.withStrategies(ReadOnlyStrategy.instance(),
+                        SubgraphStrategy.build().checkAdjacentVertices(false).vertices(hasLabel("person")).create()).
+                        V().has("name").asAdmin().getBytecode()).getScript());
+    }
+
+    @Test
+    public void shouldTranslateMaps() {
+        final String script = translator.translate(g.V().id().is(new LinkedHashMap<Object,Object>() {{
+            put(3, "32");
+            put(Arrays.asList(1, 2, 3.1d), 4);
+        }}).asAdmin().getBytecode()).getScript();
+        assertEquals("g.V().id().is(new Map([[3,\"32\"],[[1, 2, 3.1],4]]))", script);
+    }
+
+    @Test
+    public void shouldTranslateDate() {
+        final Calendar c = Calendar.getInstance();
+        c.set(1975, Calendar.SEPTEMBER, 7);
+        final Date d = c.getTime();
+        assertTranslation(String.format("new Date(%s)", d.getTime()), d);
+    }
+
+    @Test
+    public void shouldTranslateUuid() {
+        final UUID uuid = UUID.fromString("ffffffff-fd49-1e4b-0000-00000d4b8a1d");
+        assertTranslation(String.format("'%s'", uuid), uuid);
+    }
+
+    @Test
+    public void shouldTranslateColumn() {
+        assertTranslation("Column.keys", Column.keys);
+    }
+
+    @Test
+    public void shouldTranslateDirection() {
+        assertTranslation("Direction.BOTH", Direction.BOTH);
+    }
+
+    @Test
+    public void shouldTranslateOrder() {
+        assertTranslation("Order.desc", Order.desc);
+    }
+
+    @Test
+    public void shouldTranslatePop() {
+        assertTranslation("Pop.last", Pop.last);
+    }
+
+    @Test
+    public void shouldTranslateScope() {
+        assertTranslation("Scope.local", Scope.local);
+    }
+
+    @Test
+    public void shouldHaveValidToString() {
+        assertEquals("translator[h:gremlin-javascript]", JavascriptTranslator.of("h").toString());
+    }
+
+    @Test
+    public void shouldEscapeStrings() {
+        final String script = translator.translate(g.addV("customer")
+                .property("customer_id", 501L)
+                .property("name", "Foo\u0020Bar")
+                .property("age", 25)
+                .property("special", "`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?")
+                .asAdmin().getBytecode()).getScript();
+
+        assertEquals("g.addV(\"customer\")" +
+                        ".property(\"customer_id\",501)" +
+                        ".property(\"name\",\"Foo Bar\")" +
+                        ".property(\"age\",25)" +
+                        ".property(\"special\",\"\"\"`~!@#\\$%^&*()-_=+[{]}\\\\|;:'\\\",<.>/?\"\"\")",
+                script);
+    }
+
+    @Test
+    public void shouldTranslateVertexAndEdge() {
+        final Object id1 = "customer:10:foo\u0020bar\u0020\u0024100#90"; // customer:10:foo bar $100#90
+        final Vertex vertex1 = DetachedVertex.build().setLabel("customer").setId(id1)
+                .create();
+        final String script1 = translator.translate(g.inject(vertex1).asAdmin().getBytecode()).getScript();
+        assertEquals("g.inject(new Vertex(" +
+                        "\"customer:10:foo bar \\$100#90\"," +
+                        "\"customer\", null))",
+                script1);
+
+        final Object id2 = "user:20:foo\\u0020bar\\u005c\\u0022mr\\u005c\\u0022\\u00241000#50"; // user:20:foo\u0020bar\u005c\u0022mr\u005c\u0022\u00241000#50
+        final Vertex vertex2 = DetachedVertex.build().setLabel("user").setId(id2)
+                .create();
+        final String script2 = translator.translate(g.inject(vertex2).asAdmin().getBytecode()).getScript();
+        assertEquals("g.inject(new Vertex(" +
+                        "\"user:20:foo\\\\u0020bar\\\\u005c\\\\u0022mr\\\\u005c\\\\u0022\\\\u00241000#50\"," +
+                        "\"user\", null))",
+                script2);
+
+        final Object id3 = "knows:30:foo\u0020bar\u0020\u0024100:\\u0020\\u0024500#70";
+        final Edge edge = DetachedEdge.build().setLabel("knows").setId(id3)
+                .setOutV((DetachedVertex) vertex1)
+                .setInV((DetachedVertex) vertex2)
+                .create();
+        final String script3 = translator.translate(g.inject(edge).asAdmin().getBytecode()).getScript();
+        assertEquals("g.inject(" +
+                        "new Edge(\"knows:30:foo bar \\$100:\\\\u0020\\\\u0024500#70\", " +
+                        "new Vertex(\"customer:10:foo bar \\$100#90\",\"customer\", null)," +
+                        "\"knows\", " +
+                        "new Vertex(\"user:20:foo\\\\u0020bar\\\\u005c\\\\u0022mr\\\\u005c\\\\u0022\\\\u00241000#50\",\"user\",null)," +
+                        "null))",
+                script3);
+
+        final String script4 = translator.translate(
+                g.addE("knows").from(vertex1).to(vertex2).property("when", "2018/09/21")
+                        .asAdmin().getBytecode()).getScript();
+        assertEquals("g.addE(\"knows\")" +
+                        ".from_(new Vertex(\"customer:10:foo bar \\$100#90\",\"customer\", null))" +
+                        ".to(new Vertex(\"user:20:foo\\\\u0020bar\\\\u005c\\\\u0022mr\\\\u005c\\\\u0022\\\\u00241000#50\",\"user\", null))" +
+                        ".property(\"when\",\"2018/09/21\")",
+                script4);
+    }
+
+    private void assertTranslation(final String expectedTranslation, final Object... objs) {
+        final String script = translator.translate(g.inject(objs).asAdmin().getBytecode()).getScript();
+        assertEquals(String.format("g.inject(%s)", expectedTranslation), script);
+    }
+}
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/ParameterizedGroovyTranslatorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/ParameterizedGroovyTranslatorTest.java
new file mode 100644
index 0000000..f38ddeb
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/ParameterizedGroovyTranslatorTest.java
@@ -0,0 +1,366 @@
+/*
+ *  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.translator;
+
+import org.apache.tinkerpop.gremlin.jsr223.TranslatorCustomizer;
+import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.Script;
+import org.apache.tinkerpop.gremlin.process.traversal.Translator;
+import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.T;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedEdge;
+import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex;
+import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
+import org.apache.tinkerpop.gremlin.util.function.Lambda;
+import org.junit.Test;
+
+import javax.script.Bindings;
+import javax.script.SimpleBindings;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.function.Function;
+
+import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.hasLabel;
+import static org.junit.Assert.assertEquals;
+
+/**
+ *  test {@link GroovyTranslator} which return parameterized result, covers:
+ *   - parameterized script checking
+ *   - binding checking
+ *   - eval result checking
+ *
+ *  <p>
+ *  {@link GroovyTranslatorTest } is used to test {@link GroovyTranslator}, both test cases looks the same
+ *  <p>
+ *
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ * @author Stark Arya (sandszhou.zj@alibaba-inc.com)
+ */
+public class ParameterizedGroovyTranslatorTest {
+
+    private static final GraphTraversalSource g = traversal().withEmbedded(EmptyGraph.instance());
+    private static final Translator.ScriptTranslator translator = GroovyTranslator.of("g", true);
+
+    @Test
+    public void shouldHandleStrategies() throws Exception {
+        assertEquals("g.withStrategies(ReadOnlyStrategy,new SubgraphStrategy(checkAdjacentVertices: _args_0, vertices: __.hasLabel(_args_1))).V().has(_args_2)",
+                translator.translate(g.withStrategies(ReadOnlyStrategy.instance(),
+                        SubgraphStrategy.build().checkAdjacentVertices(false).vertices(hasLabel("person")).create()).
+                        V().has("name").asAdmin().getBytecode()).getScript());
+    }
+
+    @Test
+    public void shouldSupportStringSupplierLambdas() {
+        final GraphTraversal.Admin<Vertex, Integer> t = g.withSideEffect("lengthSum", 0).withSack(1)
+                .V()
+                .filter(Lambda.predicate("it.get().label().equals('person')"))
+                .flatMap(Lambda.function("it.get().vertices(Direction.OUT)"))
+                .map(Lambda.<Traverser<Object>, Integer>function("it.get().value('name').length()"))
+                .sideEffect(Lambda.consumer("{ x -> x.sideEffects(\"lengthSum\", x.<Integer>sideEffects('lengthSum') + x.get()) }"))
+                .order().by(Lambda.comparator("a,b -> a <=> b"))
+                .sack(Lambda.biFunction("{ a,b -> a + b }"))
+                .asAdmin();
+        final Script script = translator.translate(t.getBytecode());
+        final Bindings bindings = new SimpleBindings();
+        script.getParameters().ifPresent(bindings::putAll);
+        assertEquals(9, bindings.size());
+        assertEquals("lengthSum", bindings.get("_args_0"));
+        assertEquals(Integer.valueOf(0), bindings.get("_args_1"));
+        assertEquals(Integer.valueOf(1), bindings.get("_args_2"));
+        assertEquals(Lambda.predicate("it.get().label().equals('person')"), bindings.get("_args_3"));
+        assertEquals(Lambda.function("it.get().vertices(Direction.OUT)"), bindings.get("_args_4"));
+        assertEquals(Lambda.<Traverser<Object>, Integer>function("it.get().value('name').length()"), bindings.get("_args_5"));
+        assertEquals(Lambda.consumer("{ x -> x.sideEffects(\"lengthSum\", x.<Integer>sideEffects('lengthSum') + x.get()) }"), bindings.get("_args_6"));
+        assertEquals(Lambda.comparator("a,b -> a <=> b"), bindings.get("_args_7"));
+        assertEquals(Lambda.biFunction("{ a,b -> a + b }"), bindings.get("_args_8"));
+        assertEquals("g.withSideEffect(_args_0,_args_1).withSack(_args_2)" +
+                        ".V()" +
+                        ".filter(_args_3)" +
+                        ".flatMap(_args_4)" +
+                        ".map(_args_5)" +
+                        ".sideEffect(_args_6)" +
+                        ".order().by(_args_7)" +
+                        ".sack(_args_8)",
+                script.getScript());
+    }
+
+    @Test
+    public void shouldHandleArray() {
+        final Script script = translator.translate(g.V().has(T.id, P.within(new ArrayList() {{
+            add(1);
+            add(2);
+            add(3);
+            add(4);
+            add(5);
+        }})).asAdmin().getBytecode());
+        final Bindings bindings = new SimpleBindings();
+        script.getParameters().ifPresent(bindings::putAll);
+        assertEquals(5, bindings.size());
+        assertEquals(Integer.valueOf(1), bindings.get("_args_0"));
+        assertEquals(Integer.valueOf(2), bindings.get("_args_1"));
+        assertEquals(Integer.valueOf(3), bindings.get("_args_2"));
+        assertEquals(Integer.valueOf(4), bindings.get("_args_3"));
+        assertEquals(Integer.valueOf(5), bindings.get("_args_4"));
+        assertEquals("g.V().has(T.id,P.within([_args_0, _args_1, _args_2, _args_3, _args_4]))", script.getScript());
+    }
+
+    @Test
+    public void shouldHandleSet() {
+        final Script script = translator.translate(g.V().id().is(new HashSet<Object>() {{
+            add(3);
+            add(Arrays.asList(1, 2, 3.1d));
+            add(3);
+            add("3");
+        }}).asAdmin().getBytecode());
+        final Bindings bindings = new SimpleBindings();
+        script.getParameters().ifPresent(bindings::putAll);
+        assertEquals(5, bindings.size());
+        assertEquals(Integer.valueOf(3), bindings.get("_args_0"));
+        assertEquals("3", bindings.get("_args_1"));
+        assertEquals(Integer.valueOf(1), bindings.get("_args_2"));
+        assertEquals(Integer.valueOf(2), bindings.get("_args_3"));
+        assertEquals(Double.valueOf(3.1), bindings.get("_args_4"));
+        assertEquals("g.V().id().is([_args_0, _args_1, [_args_2, _args_3, _args_4]] as Set)", script.getScript());
+    }
+
+    @Test
+    public void shouldHandleMaps() {
+        final Script script = translator.translate(g.V().id().is(new LinkedHashMap<Object,Object>() {{
+            put(3, "32");
+            put(Arrays.asList(1, 2, 3.1d), 4);
+        }}).asAdmin().getBytecode());
+        final Bindings bindings = new SimpleBindings();
+        script.getParameters().ifPresent(bindings::putAll);
+        assertEquals(6, bindings.size());
+        assertEquals(Integer.valueOf(3), bindings.get("_args_0"));
+        assertEquals("32", bindings.get("_args_1"));
+        assertEquals(Integer.valueOf(1), bindings.get("_args_2"));
+        assertEquals(Integer.valueOf(2), bindings.get("_args_3"));
+        assertEquals(Double.valueOf(3.1), bindings.get("_args_4"));
+        assertEquals(Integer.valueOf(4), bindings.get("_args_5"));
+        assertEquals("g.V().id().is([(_args_0):(_args_1),([_args_2, _args_3, _args_4]):(_args_5)])", script.getScript());
+    }
+
+    @Test
+    public void shouldHandleEmptyMaps() {
+        final Function identity = new Lambda.OneArgLambda("it.get()", "gremlin-groovy");
+        final Script script = translator.translate(g.inject(Collections.emptyMap()).map(identity).asAdmin().getBytecode());
+        final Bindings bindings = new SimpleBindings();
+        script.getParameters().ifPresent(bindings::putAll);
+        assertEquals(1, bindings.size());
+        assertEquals(identity, bindings.get("_args_0"));
+        assertEquals("g.inject([]).map(_args_0)", script.getScript());
+    }
+
+    @Test
+    public void shouldIncludeCustomTypeTranslationForSomethingSilly() throws Exception {
+        final ParameterizedSillyClass notSillyEnough = ParameterizedSillyClass.from("not silly enough", 100);
+
+        // without type translation we get uglinesss
+        final Script parameterizedScriptBad = translator.translate(g.inject(notSillyEnough).asAdmin().getBytecode());
+        final Bindings bindings = new SimpleBindings();
+        parameterizedScriptBad.getParameters().ifPresent(bindings::putAll);
+        assertEquals(String.format("g.inject(%s)", "_args_0"), parameterizedScriptBad.getScript());
+        assertEquals(1, bindings.size());
+        assertEquals(notSillyEnough, bindings.get("_args_0"));
+        bindings.clear();
+
+        // with type translation we get valid gremlin
+        final Script parameterizedScriptGood = GroovyTranslator.of("g", new ParameterizedSillyClassTranslatorCustomizer().createTypeTranslator()).
+                translate(g.inject(notSillyEnough).asAdmin().getBytecode());
+        parameterizedScriptGood.getParameters().ifPresent(bindings::putAll);
+        assertEquals(2, bindings.size());
+        assertEquals(notSillyEnough.getX(), bindings.get("_args_0"));
+        assertEquals(notSillyEnough.getY(), bindings.get("_args_1"));
+        assertEquals("g.inject(org.apache.tinkerpop.gremlin.process.traversal.translator.ParameterizedGroovyTranslatorTest.ParameterizedSillyClass.from(_args_0,_args_1))",
+                parameterizedScriptGood.getScript());
+    }
+
+    @Test
+    public void shouldHaveValidToString() {
+        assertEquals("translator[h:gremlin-groovy]", GroovyTranslator.of("h", true).toString());
+    }
+
+    @Test
+    public void shouldEscapeStrings() {
+        final Script script = translator.translate(g.addV("customer")
+                .property("customer_id", 501L)
+                .property("name", "Foo\u0020Bar")
+                .property("age", 25)
+                .property("special", "`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?")
+                .asAdmin().getBytecode());
+        final Bindings bindings = new SimpleBindings();
+        script.getParameters().ifPresent(bindings::putAll);
+        assertEquals(9, bindings.size());
+        assertEquals("customer", bindings.get("_args_0"));
+        assertEquals("customer_id", bindings.get("_args_1"));
+        assertEquals(Long.valueOf(501), bindings.get("_args_2"));
+        assertEquals("name", bindings.get("_args_3"));
+        assertEquals("Foo\u0020Bar", bindings.get("_args_4"));
+        assertEquals("age", bindings.get("_args_5"));
+        assertEquals(Integer.valueOf(25), bindings.get("_args_6"));
+        assertEquals("special", bindings.get("_args_7"));
+        assertEquals("`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?", bindings.get("_args_8"));
+        assertEquals("g.addV(_args_0).property(_args_1,_args_2).property(_args_3,_args_4).property(_args_5,_args_6).property(_args_7,_args_8)", script.getScript());
+    }
+
+    @Test
+    public void shouldHandleVertexAndEdge() {
+        final Object id1 = "customer:10:foo\u0020bar\u0020\u0024100#90"; // customer:10:foo bar $100#90
+        final Vertex vertex1 = DetachedVertex.build().setLabel("customer").setId(id1)
+                .create();
+        final Script script1 = translator.translate(g.inject(vertex1).asAdmin().getBytecode());
+        final Bindings bindings = new SimpleBindings();
+        script1.getParameters().ifPresent(bindings::putAll);
+        assertEquals(2, bindings.size());
+        assertEquals(id1, bindings.get("_args_0"));
+        assertEquals("customer", bindings.get("_args_1"));
+        assertEquals("g.inject(new ReferenceVertex(_args_0,_args_1))", script1.getScript());
+        bindings.clear();
+
+        final Object id2 = "user:20:foo\\u0020bar\\u005c\\u0022mr\\u005c\\u0022\\u00241000#50"; // user:20:foo\u0020bar\u005c\u0022mr\u005c\u0022\u00241000#50
+        final Vertex vertex2 = DetachedVertex.build().setLabel("user").setId(id2)
+                .create();
+        final Script script2 = translator.translate(g.inject(vertex2).asAdmin().getBytecode());
+        script2.getParameters().ifPresent(bindings::putAll);
+        assertEquals(2, bindings.size());
+        assertEquals(id2, bindings.get("_args_0"));
+        assertEquals("user", bindings.get("_args_1"));
+        assertEquals("g.inject(new ReferenceVertex(_args_0,_args_1))", script2.getScript());
+        bindings.clear();
+
+        final Object id3 = "knows:30:foo\u0020bar\u0020\u0024100:\\u0020\\u0024500#70";
+        final Edge edge = DetachedEdge.build().setLabel("knows").setId(id3)
+                .setOutV((DetachedVertex) vertex1)
+                .setInV((DetachedVertex) vertex2)
+                .create();
+        final Script script3 = translator.translate(g.inject(edge).asAdmin().getBytecode());
+        script3.getParameters().ifPresent(bindings::putAll);
+        assertEquals(6, bindings.size());
+        assertEquals(id3, bindings.get("_args_0"));
+        assertEquals("knows", bindings.get("_args_1"));
+        assertEquals(id2, bindings.get("_args_2"));
+        assertEquals("user", bindings.get("_args_3"));
+        assertEquals(id1, bindings.get("_args_4"));
+        assertEquals("customer", bindings.get("_args_5"));
+        assertEquals("g.inject(new ReferenceEdge(_args_0,_args_1,new ReferenceVertex(_args_2,_args_3),new ReferenceVertex(_args_4,_args_5)))", script3.getScript());
+        bindings.clear();
+
+        final Script script4 = translator.translate(
+                g.addE("knows").from(vertex1).to(vertex2).property("when", "2018/09/21")
+                        .asAdmin().getBytecode());
+        script4.getParameters().ifPresent(bindings::putAll);
+        assertEquals(7, bindings.size());
+        assertEquals("knows", bindings.get("_args_0"));
+        assertEquals(id1, bindings.get("_args_1"));
+        assertEquals("customer", bindings.get("_args_2"));
+        assertEquals(id2, bindings.get("_args_3"));
+        assertEquals("user", bindings.get("_args_4"));
+        assertEquals("when", bindings.get("_args_5"));
+        assertEquals("2018/09/21", bindings.get("_args_6"));
+        assertEquals("g.addE(_args_0).from(new ReferenceVertex(_args_1,_args_2)).to(new ReferenceVertex(_args_3,_args_4)).property(_args_5,_args_6)", script4.getScript());
+        bindings.clear();
+
+        final Script script5 = translator.translate(g.V().has("age").asAdmin().getBytecode());
+        script5.getParameters().ifPresent(bindings::putAll);
+        assertEquals(1, bindings.size());
+        assertEquals("age", bindings.get("_args_0"));
+        assertEquals("g.V().has(_args_0)", script5.getScript());
+    }
+
+    public static class ParameterizedSillyClass {
+
+        private final String x;
+        private final int y;
+
+        private ParameterizedSillyClass(final String x, final int y) {
+            this.x = x;
+            this.y = y;
+        }
+
+        public static ParameterizedSillyClass from(final String x, final int y) {
+            return new ParameterizedSillyClass(x, y);
+        }
+
+        public String getX() {
+            return x;
+        }
+
+        public int getY() {
+            return y;
+        }
+
+        public Object[] getArguments() {
+            return new Object[] {x,y};
+        }
+
+        @Override
+        public String toString() {
+            return String.format("org.apache.tinkerpop.gremlin.groovy.jsr223.ParameterizedGroovyTranslatorTest.ParameterizedSillyClass.from('%s', (int) %s)", getX(), getY());
+        }
+    }
+
+    public static class ParameterizedSillyClassTranslator extends  GroovyTranslator.DefaultTypeTranslator {
+        public ParameterizedSillyClassTranslator(final boolean withParameters) {
+           super(withParameters);
+        }
+
+        @Override
+        protected Script convertToScript(final Object object) {
+            if (object instanceof ParameterizedSillyClass) {
+                ParameterizedSillyClass obj = (ParameterizedSillyClass) object;
+                script.append(obj.getClass().getCanonicalName());
+                if (0 == obj.getArguments().length) {
+                    script.append(".").append("from").append("()");
+                } else {
+                    script.append(".").append("from").append("(");
+                    for (final Object argument: obj.getArguments()) {
+                        convertToScript(argument);
+                        script.append(",");
+                    }
+                    script.setCharAtEnd(')');
+                }
+                return script;
+            } else {
+                return super.convertToScript(object);
+            }
+        }
+    }
+
+    public static class ParameterizedSillyClassTranslatorCustomizer implements TranslatorCustomizer {
+
+        @Override
+        public Translator.ScriptTranslator.TypeTranslator createTypeTranslator() {
+            return new ParameterizedSillyClassTranslator(true);
+        }
+    }
+}
+
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/PythonTranslatorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/PythonTranslatorTest.java
index 3ec6410..e89c2ed 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/PythonTranslatorTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/PythonTranslatorTest.java
@@ -46,23 +46,23 @@
     }
 
     @Test
-    public void shouldTranslate() {
+    public void shouldTranslateOption() {
         final String gremlinAsPython = translator.translate(
-                g.V().has("person", "name", "marko").asAdmin().getBytecode());
+                g.V().has("person", "name", "marko").asAdmin().getBytecode()).getScript();
         assertEquals("g.V().has('person','name','marko')", gremlinAsPython);
     }
 
     @Test
     public void shouldTranslateCardinality() {
         final String gremlinAsPython = translator.translate(
-                g.addV("person").property(VertexProperty.Cardinality.list, "name", "marko").asAdmin().getBytecode());
+                g.addV("person").property(VertexProperty.Cardinality.list, "name", "marko").asAdmin().getBytecode()).getScript();
         assertEquals("g.addV('person').property(Cardinality.list_,'name','marko')", gremlinAsPython);
     }
 
     @Test
     public void shouldTranslateMultilineStrings() {
         final String gremlinAsPython = translator.translate(
-                g.addV().property("text", "a"+ System.lineSeparator() + "\"and\"" + System.lineSeparator() + "b").asAdmin().getBytecode());
+                g.addV().property("text", "a"+ System.lineSeparator() + "\"and\"" + System.lineSeparator() + "b").asAdmin().getBytecode()).getScript();
         assertEquals("g.addV().property('text',\"\"\"a" + System.lineSeparator() + "\"and\"" + System.lineSeparator() + "b\"\"\")", gremlinAsPython);
     }
 
@@ -70,7 +70,7 @@
     public void shouldTranslateChildTraversals() {
         final String gremlinAsPython = translator.translate(
                 g.V().has("person", "name", "marko").
-                  where(outE()).asAdmin().getBytecode());
+                  where(outE()).asAdmin().getBytecode()).getScript();
         assertEquals("g.V().has('person','name','marko').where(__.outE())", gremlinAsPython);
     }
 
@@ -78,35 +78,20 @@
     public void shouldTranslatePythonNamedSteps() {
         final String gremlinAsPython = translator.translate(
                 g.V().has("person", "name", "marko").
-                        where(outE().count().is(2).and(__.not(inE().count().is(3)))).asAdmin().getBytecode());
+                        where(outE().count().is(2).and(__.not(inE().count().is(3)))).asAdmin().getBytecode()).getScript();
         assertEquals("g.V().has('person','name','marko').where(__.outE().count().is_(2).and_(__.not_(__.inE().count().is_(3))))", gremlinAsPython);
     }
 
     @Test
     public void shouldTranslateStrategies() {
-        assertEquals("g.withStrategies([TraversalStrategy('ReadOnlyStrategy'),TraversalStrategy('SubgraphStrategy',{'checkAdjacentVertices':False,'vertices':__.hasLabel('person')})]).V().has('name')",
+        assertEquals("g.withStrategies(*[TraversalStrategy('ReadOnlyStrategy', None, 'org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy'),TraversalStrategy('SubgraphStrategy',{'checkAdjacentVertices':False,'vertices':__.hasLabel('person')}, 'org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy')]).V().has('name')",
                 translator.translate(g.withStrategies(ReadOnlyStrategy.instance(),
                         SubgraphStrategy.build().checkAdjacentVertices(false).vertices(hasLabel("person")).create()).
-                        V().has("name").asAdmin().getBytecode()));
+                        V().has("name").asAdmin().getBytecode()).getScript());
     }
 
     @Test
-    public void shouldTranslatePythonLambdas() {
-        final Bytecode bytecode = g.withSideEffect("lengthSum", 0).withSack(1)
-                .V()
-                .filter(Lambda.predicate("x : x.get().label() == 'person'"))
-                .flatMap(Lambda.function("lambda x : x.get().vertices(Direction.OUT)"))
-                .map(Lambda.<Traverser<Object>, Integer>function("lambda x : len(x.get().value('name'))"))
-                .sideEffect(Lambda.consumer(" x : x.sideEffects(\"lengthSum\", x.sideEffects('lengthSum') + x.get())    "))
-                .order().by(Lambda.comparator("  lambda: a,b : 0 if a == b else 1 if a > b else -1"))
-                .sack(Lambda.biFunction("lambda: a,b : a + b"))
-                .asAdmin().getBytecode();
-        assertEquals("g.withSideEffect('lengthSum',0).withSack(1).V().filter(lambda: \"x : x.get().label() == 'person'\").flatMap(lambda: \"lambda x : x.get().vertices(Direction.OUT)\").map(lambda: \"lambda x : len(x.get().value('name'))\").sideEffect(lambda: \"x : x.sideEffects(\\\"lengthSum\\\", x.sideEffects('lengthSum') + x.get())\").order().by(lambda: \"lambda: a,b : 0 if a == b else 1 if a > b else -1\").sack(lambda: \"lambda: a,b : a + b\")",
-                translator.translate(bytecode));
-    }
-
-    @Test
-    public void shouldTranslateGroovyLambdas() {
+    public void shouldTranslateLambdas() {
         final Bytecode bytecode = g.withSideEffect("lengthSum", 0).withSack(1)
                 .V()
                 .filter(Lambda.predicate("x -> x.get().label() == 'person'", "gremlin-groovy"))
@@ -117,6 +102,6 @@
                 .sack(Lambda.biFunction("a,b -> a + b", "gremlin-groovy"))
                 .asAdmin().getBytecode();
         assertEquals("g.withSideEffect('lengthSum',0).withSack(1).V().filter(lambda: \"x -> x.get().label() == 'person'\").flatMap(lambda: \"it.get().vertices(Direction.OUT)\").map(lambda: \"x -> x : len(x.get().value('name'))\").sideEffect(lambda: \"x -> x.sideEffects(\\\"lengthSum\\\", x.sideEffects('lengthSum') + x.get())\").order().by(lambda: \"a,b -> a == b ? 0 : (a > b) ? 1 : -1)\").sack(lambda: \"a,b -> a + b\")",
-                translator.translate(bytecode));
+                translator.translate(bytecode).getScript());
     }
 }
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/EmptyTraverserTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/EmptyTraverserTest.java
new file mode 100644
index 0000000..da41900
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/EmptyTraverserTest.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.traverser.util;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+
+public class EmptyTraverserTest {
+
+    @Test
+    public void shouldHaveSameInstance() {
+        assertSame(EmptyTraverser.instance(), EmptyTraverser.instance());
+    }
+
+    @Test
+    public void shouldHaveZeroBulk() {
+        assertEquals(0, EmptyTraverser.instance().bulk());
+    }
+}
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/IndexedTraverserSetTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/IndexedTraverserSetTest.java
index 0d765f4..6f0b490 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/IndexedTraverserSetTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/IndexedTraverserSetTest.java
@@ -26,6 +26,7 @@
 import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.List;
+import java.util.Random;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.core.IsNull.nullValue;
@@ -111,7 +112,7 @@
         assertEquals(1, nopeTraversers.size());
         assertEquals(1, nopeTraversers.get(0).bulk());
 
-        ts.shuffle();
+        ts.shuffle(new Random());
 
         final List<Traverser.Admin<String>> testTraversersAfterShuffle = new ArrayList<>(ts.get("test"));
         assertEquals(1, testTraversersAfterShuffle.size());
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/BytecodeHelperTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/BytecodeHelperTest.java
index 24a94aa..df4011e 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/BytecodeHelperTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/BytecodeHelperTest.java
@@ -18,15 +18,12 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.util;
 
-import org.apache.tinkerpop.gremlin.jsr223.JavaTranslator;
 import org.apache.tinkerpop.gremlin.process.traversal.Bindings;
 import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
-import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.OptionsStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy;
-import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
 import org.apache.tinkerpop.gremlin.util.function.Lambda;
 import org.junit.Test;
@@ -35,6 +32,8 @@
 import java.util.Optional;
 import java.util.stream.Stream;
 
+import static org.apache.tinkerpop.gremlin.process.traversal.GraphOp.TX_COMMIT;
+import static org.apache.tinkerpop.gremlin.process.traversal.GraphOp.TX_ROLLBACK;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.core.Is.is;
 import static org.junit.Assert.assertEquals;
@@ -94,4 +93,11 @@
                 bc, i -> Stream.of(i.getArguments()).anyMatch(o -> o instanceof Bytecode.Binding));
         assertEquals(0, filteredAfterRemoved.getStepInstructions().size());
     }
+
+    @Test
+    public void shouldDetermineOperation() {
+        assertThat(BytecodeHelper.isGraphOperation(TX_COMMIT.getBytecode()), is(true));
+        assertThat(BytecodeHelper.isGraphOperation(TX_ROLLBACK.getBytecode()), is(true));
+        assertThat(BytecodeHelper.isGraphOperation(g.V().out("knows").asAdmin().getBytecode()), is(false));
+    }
 }
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/DefaultTraversalStrategiesTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/DefaultTraversalStrategiesTest.java
index c63ed93..cf1c694 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/DefaultTraversalStrategiesTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/DefaultTraversalStrategiesTest.java
@@ -26,7 +26,8 @@
 import org.junit.Test;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -48,9 +49,20 @@
             o = new TraversalStrategiesTest.StrategyO();
 
     @Test
+    public void testNoRepeatStrategies() {
+        final TraversalStrategies s = new DefaultTraversalStrategies();
+        s.addStrategies(b, a, d, b, a, a, d, d);
+        s.addStrategies(new TraversalStrategiesTest.StrategyD(), new TraversalStrategiesTest.StrategyB());
+        assertEquals(3, s.toList().size());
+        assertEquals(a, s.toList().get(0));
+        assertEquals(b, s.toList().get(1));
+        assertEquals(d, s.toList().get(2));
+    }
+
+    @Test
     public void testWellDefinedDependency() {
         //Dependency well defined
-        TraversalStrategies s = new DefaultTraversalStrategies();
+        final TraversalStrategies s = new DefaultTraversalStrategies();
         s.addStrategies(b, a);
         assertEquals(2, s.toList().size());
         assertEquals(a, s.toList().get(0));
@@ -60,7 +72,7 @@
     @Test
     public void testNoDependency() {
         //No dependency
-        TraversalStrategies s = new DefaultTraversalStrategies();
+        final TraversalStrategies s = new DefaultTraversalStrategies();
         s.addStrategies(c, a);
         assertEquals(2, s.toList().size());
     }
@@ -84,7 +96,7 @@
     @Test
     public void testCircularDependency() {
         //Circular dependency => throws exception
-        TraversalStrategies s = new DefaultTraversalStrategies();
+        final TraversalStrategies s = new DefaultTraversalStrategies();
         try {
             s.addStrategies(c, k, a, b);
             fail();
@@ -116,7 +128,7 @@
     @Test
     public void testCircularDependency2() {
         //Circular dependency => throws exception
-        TraversalStrategies s = new DefaultTraversalStrategies();
+        final TraversalStrategies s = new DefaultTraversalStrategies();
         try {
             s.addStrategies(d, c, k, a, e, b);
             fail();
@@ -199,10 +211,10 @@
         assertEquals(1, fifthTraversal.getSideEffects().keys().size());
         assertEquals(2, fifthTraversal.getSideEffects().<Integer>get("a").intValue());
 
-        assertTrue(firstTraversal.getStrategies() == secondTraversal.getStrategies());
-        assertTrue(firstTraversal.getStrategies() != thirdTraversal.getStrategies());
-        assertTrue(forthTraversal.getStrategies() == thirdTraversal.getStrategies());
-        assertTrue(fifthTraversal.getStrategies() == firstTraversal.getStrategies());
+        assertSame(firstTraversal.getStrategies(), secondTraversal.getStrategies());
+        assertNotSame(firstTraversal.getStrategies(), thirdTraversal.getStrategies());
+        assertSame(forthTraversal.getStrategies(), thirdTraversal.getStrategies());
+        assertSame(fifthTraversal.getStrategies(), firstTraversal.getStrategies());
     }
 }
 
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/DefaultTraversalTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/DefaultTraversalTest.java
index 8912b0c..0816dc0 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/DefaultTraversalTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/DefaultTraversalTest.java
@@ -42,16 +42,14 @@
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
 
-import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.is;
 import static org.hamcrest.number.OrderingComparison.greaterThan;
 import static org.hamcrest.number.OrderingComparison.lessThan;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalExplanationTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalExplanationTest.java
index 0a81238..89a37d5 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalExplanationTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalExplanationTest.java
@@ -130,8 +130,9 @@
         }
         assertEquals(4, found);
         //
+        //System.out.println(traversal.explain().prettyPrint(160));
         found = 0;
-        for (final String line : traversal.explain().prettyPrint(158).split("]\n")) { // need to split cause of word wrap
+        for (final String line : traversal.explain().prettyPrint(170).split("]\n")) { // need to split cause of word wrap
             if (line.contains("IncidentToAdjacentStrategy") && line.contains("[VertexStep(IN,vertex)"))
                 found++;
             if (line.contains("IncidentToAdjacentStrategy") && line.contains("[VertexStep(OUT,vertex)"))
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelperTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelperTest.java
index 74ef6a4..66ef474 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelperTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelperTest.java
@@ -59,7 +59,7 @@
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertTrue;
 
 /**
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoPoolTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoPoolTest.java
index f9029bb..aaded07 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoPoolTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoPoolTest.java
@@ -18,8 +18,9 @@
  */
 package org.apache.tinkerpop.gremlin.structure.io.gryo;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.configuration2.convert.LegacyListDelimiterHandler;
 import org.apache.tinkerpop.gremlin.structure.io.IoRegistry;
 import org.apache.tinkerpop.gremlin.structure.io.IoX;
 import org.apache.tinkerpop.gremlin.structure.io.IoXIoRegistry;
@@ -103,6 +104,7 @@
     @Test
     public void shouldConfigPoolOnConstructionWithMultipleCustomIoRegistries() throws Exception {
         final Configuration conf = new BaseConfiguration();
+        ((BaseConfiguration) conf).setListDelimiterHandler(new LegacyListDelimiterHandler(','));
         conf.setProperty(IoRegistry.IO_REGISTRY,
                 IoXIoRegistry.InstanceBased.class.getName() + "," + IoYIoRegistry.InstanceBased.class.getName());
         final GryoPool pool = GryoPool.build().ioRegistries(conf.getList(IoRegistry.IO_REGISTRY, Collections.emptyList())).create();
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/util/ElementHelperTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/util/ElementHelperTest.java
index 636859d..e9b066d 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/util/ElementHelperTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/util/ElementHelperTest.java
@@ -54,13 +54,8 @@
     }
 
     @Test
-    public void shouldValidatePropertyAndNotAllowNullValue() {
-        try {
-            ElementHelper.validateProperty("test", null);
-            fail("Should fail as property value cannot be null");
-        } catch (IllegalArgumentException iae) {
-            assertEquals(Property.Exceptions.propertyValueCanNotBeNull().getMessage(), iae.getMessage());
-        }
+    public void shouldValidatePropertyAndAllowNullValue() {
+        ElementHelper.validateProperty("test", null);
     }
 
     @Test
@@ -125,15 +120,6 @@
     }
 
     @Test
-    public void shouldNotAllowEvenNumberOfKeyValuesAndInvalidValues() {
-        try {
-            ElementHelper.legalPropertyKeyValueArray("aKey", "test", "value-for-this-one", 1, "1", null);
-        } catch (IllegalArgumentException iae) {
-            assertEquals(Property.Exceptions.propertyValueCanNotBeNull().getMessage(), iae.getMessage());
-        }
-    }
-
-    @Test
     public void shouldFindTheIdValueAlone() {
         assertEquals(123l, ElementHelper.getIdValue(T.id, 123l).get());
     }
@@ -148,9 +134,9 @@
         assertFalse(ElementHelper.getIdValue("test", 321, "xyz", 123l, "testagain", "that").isPresent());
     }
 
-    @Test(expected = NullPointerException.class)
+    @Test
     public void shouldNotFindAnIdValueBecauseItIsNull() {
-        ElementHelper.getIdValue("test", 321, T.id, null, "testagain", "that");
+        assertEquals("default", ElementHelper.getIdValue("test", 321, T.id, null, "testagain", "that").orElse("default"));
     }
 
     @Test
@@ -191,6 +177,15 @@
     @Test
     public void shouldAttachPropertiesButNotLabelsOrId() {
         final Element mockElement = mock(Element.class);
+        final Graph mockGraph = mock(Graph.class);
+        final Graph.Features mockGraphFeatures = mock(Graph.Features.class);
+        final Graph.Features.VertexFeatures mockVertexFeatures = mock(Graph.Features.VertexFeatures.class);
+        final Graph.Features.VertexPropertyFeatures mockVertexPropertyFeatures = mock(Graph.Features.VertexPropertyFeatures.class);
+        when(mockElement.graph()).thenReturn(mockGraph);
+        when(mockGraph.features()).thenReturn(mockGraphFeatures);
+        when(mockGraphFeatures.vertex()).thenReturn(mockVertexFeatures);
+        when(mockVertexFeatures.properties()).thenReturn(mockVertexPropertyFeatures);
+        when(mockVertexPropertyFeatures.supportsNullPropertyValues()).thenReturn(true);
         ElementHelper.attachProperties(mockElement, "test", 123, T.id, 321, T.label, "friends");
         verify(mockElement, times(1)).property("test", 123);
         verify(mockElement, times(0)).property(T.id.getAccessor(), 321);
@@ -200,6 +195,15 @@
     @Test(expected = ClassCastException.class)
     public void shouldFailTryingToAttachPropertiesNonStringKey() {
         final Element mockElement = mock(Element.class);
+        final Graph mockGraph = mock(Graph.class);
+        final Graph.Features mockGraphFeatures = mock(Graph.Features.class);
+        final Graph.Features.VertexFeatures mockVertexFeatures = mock(Graph.Features.VertexFeatures.class);
+        final Graph.Features.VertexPropertyFeatures mockVertexPropertyFeatures = mock(Graph.Features.VertexPropertyFeatures.class);
+        when(mockElement.graph()).thenReturn(mockGraph);
+        when(mockGraph.features()).thenReturn(mockGraphFeatures);
+        when(mockGraphFeatures.vertex()).thenReturn(mockVertexFeatures);
+        when(mockVertexFeatures.properties()).thenReturn(mockVertexPropertyFeatures);
+        when(mockVertexPropertyFeatures.supportsNullPropertyValues()).thenReturn(true);
         ElementHelper.attachProperties(mockElement, "test", 123, 321, "test");
     }
 
@@ -216,6 +220,15 @@
     @Test
     public void shouldAttachPropertiesWithCardinalityButNotLabelsOrId() {
         final Vertex mockElement = mock(Vertex.class);
+        final Graph mockGraph = mock(Graph.class);
+        final Graph.Features mockGraphFeatures = mock(Graph.Features.class);
+        final Graph.Features.VertexFeatures mockVertexFeatures = mock(Graph.Features.VertexFeatures.class);
+        final Graph.Features.VertexPropertyFeatures mockVertexPropertyFeatures = mock(Graph.Features.VertexPropertyFeatures.class);
+        when(mockElement.graph()).thenReturn(mockGraph);
+        when(mockGraph.features()).thenReturn(mockGraphFeatures);
+        when(mockGraphFeatures.vertex()).thenReturn(mockVertexFeatures);
+        when(mockVertexFeatures.properties()).thenReturn(mockVertexPropertyFeatures);
+        when(mockVertexPropertyFeatures.supportsNullPropertyValues()).thenReturn(true);
         ElementHelper.attachProperties(mockElement, VertexProperty.Cardinality.single, "test", 123, T.id, 321, T.label, "friends");
         verify(mockElement, times(1)).property(VertexProperty.Cardinality.single, "test", 123);
         verify(mockElement, times(0)).property(VertexProperty.Cardinality.single, T.id.getAccessor(), 321);
@@ -225,6 +238,15 @@
     @Test(expected = ClassCastException.class)
     public void shouldFailTryingToAttachPropertiesWithCardinalityNonStringKey() {
         final Element mockElement = mock(Vertex.class);
+        final Graph mockGraph = mock(Graph.class);
+        final Graph.Features mockGraphFeatures = mock(Graph.Features.class);
+        final Graph.Features.VertexFeatures mockVertexFeatures = mock(Graph.Features.VertexFeatures.class);
+        final Graph.Features.VertexPropertyFeatures mockVertexPropertyFeatures = mock(Graph.Features.VertexPropertyFeatures.class);
+        when(mockElement.graph()).thenReturn(mockGraph);
+        when(mockGraph.features()).thenReturn(mockGraphFeatures);
+        when(mockGraphFeatures.vertex()).thenReturn(mockVertexFeatures);
+        when(mockVertexFeatures.properties()).thenReturn(mockVertexPropertyFeatures);
+        when(mockVertexPropertyFeatures.supportsNullPropertyValues()).thenReturn(true);
         ElementHelper.attachProperties(mockElement, VertexProperty.Cardinality.single, "test", 123, 321, "test");
     }
 
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/util/GraphFactoryTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/util/GraphFactoryTest.java
index 701e159..4a933d5 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/util/GraphFactoryTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/util/GraphFactoryTest.java
@@ -18,8 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.structure.util;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.AssertHelper;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
 import org.apache.tinkerpop.gremlin.structure.Edge;
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/util/detached/DetachedFactoryTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/util/detached/DetachedFactoryTest.java
index 4f65e0e..5b686ed 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/util/detached/DetachedFactoryTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/util/detached/DetachedFactoryTest.java
@@ -21,17 +21,15 @@
 import org.apache.tinkerpop.gremlin.process.traversal.Path;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.MutablePath;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
-import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex;
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 import org.junit.Test;
 
 import java.util.Collections;
 import java.util.List;
 
-import static org.hamcrest.core.Is.is;
 import static org.hamcrest.core.IsInstanceOf.instanceOf;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 
 /**
  * @author Stephen Mallette (http://stephen.genoprime.com)
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/util/reference/ReferenceFactoryTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/util/reference/ReferenceFactoryTest.java
index 646817f..30dc987 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/util/reference/ReferenceFactoryTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/util/reference/ReferenceFactoryTest.java
@@ -30,7 +30,7 @@
 
 import static org.hamcrest.core.Is.is;
 import static org.hamcrest.core.IsInstanceOf.instanceOf;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 
 /**
  * @author Stephen Mallette (http://stephen.genoprime.com)
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/SystemUtilTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/SystemUtilTest.java
index e5dc705..3705b99 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/SystemUtilTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/SystemUtilTest.java
@@ -19,7 +19,7 @@
 
 package org.apache.tinkerpop.gremlin.util;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 import org.junit.Test;
 
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/config/YamlConfigurationTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/config/YamlConfigurationTest.java
deleted file mode 100644
index e823dd3..0000000
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/config/YamlConfigurationTest.java
+++ /dev/null
@@ -1,135 +0,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.
- */
-package org.apache.tinkerpop.gremlin.util.config;
-
-import org.apache.commons.configuration.ConfigurationException;
-import org.junit.Test;
-import org.yaml.snakeyaml.DumperOptions;
-import org.yaml.snakeyaml.Yaml;
-
-import java.io.Reader;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.io.Writer;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * @author Stephen Mallette (http://stephen.genoprime.com)
- */
-public class YamlConfigurationTest {
-
-    @Test(expected = ConfigurationException.class)
-    public void shouldThrowConfigurationExceptionIfLoadFails() throws Exception {
-        final YamlConfiguration config = new YamlConfiguration();
-        config.load((Reader) null);
-    }
-
-    @Test(expected = ConfigurationException.class)
-    public void shouldThrowConfigurationExceptionIfSaveFails() throws Exception {
-        final YamlConfiguration config = new YamlConfiguration();
-        config.save((Writer) null);
-    }
-
-    @Test
-    public void shouldLoadSaveConfiguration() throws Exception {
-        final YamlConfiguration config = new YamlConfiguration();
-        final String testData = this.getTestInputData();
-        final StringWriter writer = new StringWriter();
-        config.load(new StringReader(testData));
-        config.save(writer);
-
-        assertEquals(testData, writer.getBuffer().toString());
-    }
-
-    @Test
-    public void shouldNavigationConfiguration() throws Exception {
-        final Map<Object, Object> testData = this.getTestData();
-        final YamlConfiguration config = new YamlConfiguration();
-        config.load(new StringReader(this.getTestInputData()));
-
-        assertEquals(testData.get("integer"), config.getInt("integer"));
-        assertEquals(testData.get("string"), config.getString("string"));
-        assertEquals(testData.get("long"), config.getLong("long"));
-        assertEquals(testData.get("true-boolean"), config.getBoolean("true-boolean"));
-        assertEquals(testData.get("false-boolean"), config.getBoolean("false-boolean"));
-        assertEquals(testData.get("list"), config.getList("list.item"));
-        assertEquals(testData.get("42"), config.getString("42"));
-
-        final Map<Object, Object> subData = this.getSubMap();
-        assertEquals(subData.get("sub-string"), config.getString("map.sub-string"));
-        assertEquals("String1", config.getString("map.sub-list.item(1).item(0)"));
-    }
-
-    @Test
-    public void shouldSupportXMLCompatibility() throws Exception {
-        final YamlConfiguration config = new YamlConfiguration();
-        config.setXmlCompatibility(true);
-        config.load(new StringReader(this.getTestInputData()));
-        assertEquals(Arrays.asList("testUser1-Data", "testUser2-Data"), config.getList("users.user.item"));
-    }
-
-    private String getTestInputData() {
-        final DumperOptions yamlOptions = new DumperOptions();
-        Yaml yaml = new Yaml(yamlOptions);
-
-        yamlOptions.setIndent(YamlConfiguration.DEFAULT_IDENT);
-        yamlOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
-
-        return yaml.dump(this.getTestData());
-    }
-
-    private Map<Object, Object> getTestData() {
-        final HashMap<Object, Object> result = new LinkedHashMap<>();
-
-        result.put("integer", Integer.MIN_VALUE);
-        result.put("string", "String Value");
-        result.put("long", Long.MAX_VALUE);
-        result.put("true-boolean", true);
-        result.put("false-boolean", false);
-        result.put("list", Arrays.asList(1, 2, 3, 4, 5));
-        result.put("42", "The Answer");
-        result.put("map", getSubMap());
-
-        final Map<Object, Object> users = new LinkedHashMap<>();
-        users.put("testUser1", Arrays.asList("testUser1-Data"));
-        users.put("testUser2", Arrays.asList("testUser2-Data"));
-        result.put("users", users);
-
-        //result.put("tricky-list", Arrays.asList(Arrays.asList(Arrays.asList(leafMap.keySet()), leafMap.values())));
-
-        return result;
-    }
-
-    private Map<Object, Object> getSubMap() {
-        final Map<Object, Object> subMap = new LinkedHashMap<>();
-        subMap.put("sub-string", "The String!");
-
-        final Map<Object, Object> leafMap = new LinkedHashMap<>();
-        leafMap.put("test", "value");
-        leafMap.put("long", Long.MIN_VALUE);
-
-        subMap.put("sub-list", Arrays.asList(Integer.MIN_VALUE, Arrays.asList("String1", "String2"), Boolean.TRUE, leafMap));
-        return subMap;
-    }
-}
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/iterator/ArrayIteratorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/iterator/ArrayIteratorTest.java
index 60ddd88..2293277 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/iterator/ArrayIteratorTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/iterator/ArrayIteratorTest.java
@@ -25,6 +25,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
 
 /**
  * @author Stephen Mallette (http://stephen.genoprime.com)
@@ -45,6 +46,21 @@
         assertFalse(itty.hasNext());
     }
 
+    @Test
+    public void shouldIterateAnArrayWithNull() {
+        final String[] arr = new String[3];
+        arr[0] = "test1";
+        arr[1] = "test2";
+        arr[2] = null;
+
+        final Iterator<String> itty = new ArrayIterator<>(arr);
+        assertEquals("test1", itty.next());
+        assertEquals("test2", itty.next());
+        assertNull(itty.next());
+
+        assertFalse(itty.hasNext());
+    }
+
     @Test(expected = FastNoSuchElementException.class)
     public void shouldThrowFastNoSuchElementException() {
         final Iterator<String> itty = new ArrayIterator<>(new String[0]);
diff --git a/gremlin-dotnet/Gremlin.Net.sln b/gremlin-dotnet/Gremlin.Net.sln
index 3f2b2b4..8816c76 100644
--- a/gremlin-dotnet/Gremlin.Net.sln
+++ b/gremlin-dotnet/Gremlin.Net.sln
@@ -19,6 +19,8 @@
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Gremlin.Net.Template.IntegrationTest", "test\Gremlin.Net.Template.IntegrationTest\Gremlin.Net.Template.IntegrationTest.csproj", "{3BFC3559-E317-4327-AFB7-CFBB31E1C868}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Gremlin.Net.Benchmarks", "test\Gremlin.Net.Benchmarks\Gremlin.Net.Benchmarks.csproj", "{7250A8B5-B962-49AB-B295-F75F8D4DBD78}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -45,6 +47,10 @@
 		{3BFC3559-E317-4327-AFB7-CFBB31E1C868}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{3BFC3559-E317-4327-AFB7-CFBB31E1C868}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{3BFC3559-E317-4327-AFB7-CFBB31E1C868}.Release|Any CPU.Build.0 = Release|Any CPU
+		{7250A8B5-B962-49AB-B295-F75F8D4DBD78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{7250A8B5-B962-49AB-B295-F75F8D4DBD78}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{7250A8B5-B962-49AB-B295-F75F8D4DBD78}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{7250A8B5-B962-49AB-B295-F75F8D4DBD78}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -55,6 +61,7 @@
 		{CC54ABE3-13D2-491C-81E2-4D0355ABFA93} = {1B54FAC2-5411-4BB6-B450-FE2FFD8C4782}
 		{A9D2567A-6FD0-452B-A2F9-4256FE513ADD} = {584F838B-DAE2-44F5-868C-1F532949C827}
 		{3BFC3559-E317-4327-AFB7-CFBB31E1C868} = {1B54FAC2-5411-4BB6-B450-FE2FFD8C4782}
+		{7250A8B5-B962-49AB-B295-F75F8D4DBD78} = {1B54FAC2-5411-4BB6-B450-FE2FFD8C4782}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {F0AF408C-2147-434A-80FB-73A1626FC30C}
diff --git a/gremlin-dotnet/build/generate.groovy b/gremlin-dotnet/build/generate.groovy
new file mode 100644
index 0000000..ad7a160
--- /dev/null
+++ b/gremlin-dotnet/build/generate.groovy
@@ -0,0 +1,168 @@
+/*
+ * 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.
+ */
+
+import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph
+import org.apache.tinkerpop.gremlin.process.traversal.translator.DotNetTranslator
+import org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine
+import org.apache.tinkerpop.gremlin.groovy.jsr223.ast.VarAsBindingASTTransformation
+import org.apache.tinkerpop.gremlin.groovy.jsr223.ast.RepeatASTTransformationCustomizer
+import org.apache.tinkerpop.gremlin.groovy.jsr223.GroovyCustomizer
+import org.codehaus.groovy.control.customizers.CompilationCustomizer
+import org.apache.tinkerpop.gremlin.features.FeatureReader
+
+import javax.script.SimpleBindings
+
+import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal
+
+// file is overwritten on each generation
+radishGremlinFile = new File("${projectBaseDir}/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs")
+
+// assumes globally unique scenario names for keys with list of Gremlin traversals as they appear
+gremlins = FeatureReader.parse("${projectBaseDir}")
+
+gremlinGroovyScriptEngine = new GremlinGroovyScriptEngine(new GroovyCustomizer() {
+    public CompilationCustomizer create() {
+        return new RepeatASTTransformationCustomizer(new VarAsBindingASTTransformation())
+    }
+})
+translator = DotNetTranslator.of('g')
+g = traversal().withGraph(EmptyGraph.instance())
+bindings = new SimpleBindings()
+bindings.put('g', g)
+
+radishGremlinFile.withWriter('UTF-8') { Writer writer ->
+    writer.writeLine('#region License\n' +
+            '\n' +
+            '/*\n' +
+            ' * Licensed to the Apache Software Foundation (ASF) under one\n' +
+            ' * or more contributor license agreements.  See the NOTICE file\n' +
+            ' * distributed with this work for additional information\n' +
+            ' * regarding copyright ownership.  The ASF licenses this file\n' +
+            ' * to you under the Apache License, Version 2.0 (the\n' +
+            ' * "License"); you may not use this file except in compliance\n' +
+            ' * with the License.  You may obtain a copy of the License at\n' +
+            ' *\n' +
+            ' *     http://www.apache.org/licenses/LICENSE-2.0\n' +
+            ' *\n' +
+            ' * Unless required by applicable law or agreed to in writing,\n' +
+            ' * software distributed under the License is distributed on an\n' +
+            ' * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n' +
+            ' * KIND, either express or implied.  See the License for the\n' +
+            ' * specific language governing permissions and limitations\n' +
+            ' * under the License.\n' +
+            ' */\n' +
+            '\n' +
+            '#endregion\n')
+
+    writer.writeLine("\n\n//********************************************************************************")
+    writer.writeLine("//* Do NOT edit this file directly - generated by build/generate.groovy")
+    writer.writeLine("//********************************************************************************\n\n")
+
+    writer.writeLine('using System;\n' +
+                     'using System.Collections.Generic;\n' +
+                     'using Gremlin.Net.Structure;\n' +
+                     'using Gremlin.Net.Process.Traversal;\n' +
+                     'using Gremlin.Net.Process.Traversal.Strategy.Decoration;\n')
+    writer.writeLine('namespace Gremlin.Net.IntegrationTest.Gherkin\n' +
+            '{\n' +
+            '    public class Gremlin\n' +
+            '    {\n' +
+            '        public static void InstantiateTranslationsForTestRun()\n' +
+            '        {\n' +
+            '            // We need to copy the fixed translations as we remove translations from the list after using them\n' +
+            '            // so we can enumerate through the translations while evaluating a scenario.\n' +
+            '            _translationsForTestRun =\n' +
+            '                new Dictionary<string, List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>>(\n' +
+            '                    FixedTranslations.Count);\n' +
+            '            foreach (var (traversal, translations) in FixedTranslations)\n' +
+            '            {\n' +
+            '                _translationsForTestRun.Add(traversal,\n' +
+            '                    new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>(translations));\n' +
+            '            }\n' +
+            '        }\n')
+    writer.writeLine(
+            '        private static IDictionary<string, List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>>\n' +
+            '            _translationsForTestRun;\n')
+    writer.writeLine(
+            '        private static readonly IDictionary<string, List<Func<GraphTraversalSource, IDictionary<string, object>,ITraversal>>> FixedTranslations = \n' +
+            '            new Dictionary<string, List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>>\n' +
+            '            {')
+
+    gremlins.each { k,v ->
+        writer.write("               {\"")
+        writer.write(k)
+        writer.write("\", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {")
+        def collected = v.collect{
+            def t = gremlinGroovyScriptEngine.eval(it, bindings)
+            [t, t.bytecode.bindings.keySet()]
+        }
+
+        def gremlinItty = collected.iterator()
+        while (gremlinItty.hasNext()) {
+            def t = gremlinItty.next()[0]
+            writer.write("(g,p) =>")
+            writer.write(translator.translate(t.bytecode).script.
+                    replace("xx1", "p[\"xx1\"]").
+                    replace("xx2", "p[\"xx2\"]").
+                    replace("xx3", "p[\"xx3\"]").
+                    replace("v1", "(Vertex) p[\"v1\"]").
+                    replace("v2", "(Vertex) p[\"v2\"]").
+                    replace("v3", "(Vertex) p[\"v3\"]").
+                    replace("v4", "(Vertex) p[\"v4\"]").
+                    replace("v5", "(Vertex) p[\"v5\"]").
+                    replace("v6", "(Vertex) p[\"v6\"]").
+                    replace("vid1", "p[\"vid1\"]").
+                    replace("vid2", "p[\"vid2\"]").
+                    replace("vid3", "p[\"vid3\"]").
+                    replace("vid4", "p[\"vid4\"]").
+                    replace("vid5", "p[\"vid5\"]").
+                    replace("vid6", "p[\"vid6\"]").
+                    replace("e7", "p[\"e7\"]").
+                    replace("e10", "p[\"e10\"]").
+                    replace("e11", "p[\"e11\"]").
+                    replace("eid7", "p[\"eid7\"]").
+                    replace("eid10", "p[\"eid10\"]").
+                    replace("eid11", "p[\"eid11\"]").
+                    replace("l1", "(IFunction) p[\"l1\"]").
+                    replace("l2", "(IFunction) p[\"l2\"]").
+                    replace("pred1", "(IPredicate) p[\"pred1\"]").
+                    replace("c1", "(IComparator) p[\"c1\"]").
+                    replace("c2", "(IComparator) p[\"c2\"]"))
+            if (gremlinItty.hasNext())
+                writer.write(', ')
+            else
+                writer.write("}")
+        }
+        writer.writeLine('}, ')
+    }
+    writer.writeLine('            };\n')
+
+    writer.writeLine(
+            '        public static ITraversal UseTraversal(string scenarioName, GraphTraversalSource g, IDictionary<string, object> parameters)\n' +
+            '        {\n' +
+            '            List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> list = _translationsForTestRun[scenarioName];\n' +
+            '            Func<GraphTraversalSource, IDictionary<string, object>, ITraversal> f = list[0];\n' +
+            '            list.RemoveAt(0);\n' +
+            '            return f.Invoke(g, parameters);\n' +
+            '        }\n' +
+            '    }\n' +
+            '}\n')
+}
+
+
diff --git a/gremlin-dotnet/glv/AnonymousTraversal.template b/gremlin-dotnet/glv/AnonymousTraversal.template
deleted file mode 100644
index 6b1de9c..0000000
--- a/gremlin-dotnet/glv/AnonymousTraversal.template
+++ /dev/null
@@ -1,59 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-using System.Collections.Generic;
-using Gremlin.Net.Structure;
-
-// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml
-namespace Gremlin.Net.Process.Traversal
-{
-    /// <summary>
-    ///     An anonymous <see cref="GraphTraversal{SType, EType}" />.
-    /// </summary>
-    public static class __
-    {
-        /// <summary>
-        ///     Starts an empty <see cref="GraphTraversal{SType, EType}" />.
-        /// </summary>
-        public static GraphTraversal<object, object> Start()
-        {
-            return new GraphTraversal<object, object>();
-        }
-<% anonStepMethods.each { method -> %>
-        /// <summary>
-        ///     Spawns a <see cref="GraphTraversal{SType, EType}" /> and adds the <%= method.methodName %> step to that traversal.
-        /// </summary>
-        public static GraphTraversal<object, <%= method.t2 %>> <%= toCSharpMethodName.call(method.methodName) %><%= method.tParam %>(<%= method.parameters %>)
-        {
-        <%  if (method.parameters.contains("params ")) {
-      %>    return <%= method.paramNames.last() %>.Length == 0
-                ? new GraphTraversal<object, <%= method.graphTraversalT2 %>>().<%= toCSharpMethodName.call(method.methodName) %><%= method.callGenericTypeArg %>(<%= method.paramNames.init().join(", ") %>)
-                : new GraphTraversal<object, <%= method.graphTraversalT2 %>>().<%= toCSharpMethodName.call(method.methodName) %><%= method.callGenericTypeArg %>(<%= method.paramNames.join(", ") %>);<%
-            }
-            else {
-      %>    return new GraphTraversal<object, <%= method.graphTraversalT2 %>>().<%= toCSharpMethodName.call(method.methodName) %><%= method.callGenericTypeArg %>(<%= method.paramNames.join(", ") %>);<%
-            } %>            
-        }
-<% } %>
-    }
-}
\ No newline at end of file
diff --git a/gremlin-dotnet/glv/Enum.template b/gremlin-dotnet/glv/Enum.template
deleted file mode 100644
index e785cd0..0000000
--- a/gremlin-dotnet/glv/Enum.template
+++ /dev/null
@@ -1,69 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml
-using System;
-using System.Collections.Generic;
-
-namespace Gremlin.Net.Process.Traversal
-{
-#pragma warning disable 1591
-
-    public class <%= enumClass.simpleName %> : <%= implementedTypes %>
-    {
-        private <%= enumClass.simpleName %>(string enumValue)
-            : base("<%= enumClass.simpleName %>", enumValue)
-        {
-        }
-<%
-    def toCSharpName = { enumClass, itemName ->
-        if (enumClass.equals(directionClass)) {
-            itemName = itemName.toLowerCase()
-        }
-
-        return itemName.substring(0, 1).toUpperCase() + itemName.substring(1)
-    }
-    constants.each { value -> %>
-        public static ${enumClass.simpleName} ${toCSharpName(enumClass, value.name())} => new ${enumClass.simpleName}("${value.name()}");
-<%  }%>
-        private static readonly IDictionary<string, <%= enumClass.simpleName %>> Properties = new Dictionary<string, <%= enumClass.simpleName %>>
-        {<%  constants.each { value -> %>
-            { "${value.name()}", ${toCSharpName(enumClass, value.name())} },<%  }%>
-        };
-
-        /// <summary>
-        /// Gets the <%= enumClass.simpleName %> enumeration by value.
-        /// </summary>
-        public static <%= enumClass.simpleName %> GetByValue(string value)
-        {
-            if (!Properties.TryGetValue(value, out var property))
-            {
-                throw new ArgumentException(\$"No matching <%= enumClass.simpleName%> for value '{value}'");
-            }
-            return property;
-        }
-    }
-
-
-#pragma warning restore 1591
-}
\ No newline at end of file
diff --git a/gremlin-dotnet/glv/GraphTraversal.template b/gremlin-dotnet/glv/GraphTraversal.template
deleted file mode 100644
index 430968d..0000000
--- a/gremlin-dotnet/glv/GraphTraversal.template
+++ /dev/null
@@ -1,92 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-using System.Collections.Generic;
-using System.Linq;
-using Gremlin.Net.Structure;
-
-// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml
-namespace Gremlin.Net.Process.Traversal
-{
-    /// <summary>
-    ///     Graph traversals are the primary way in which graphs are processed.
-    /// </summary>
-    public class GraphTraversal<S, E> : DefaultTraversal<S, E>
-    {
-        /// <summary>
-        ///     Initializes a new instance of the <see cref="GraphTraversal{SType, EType}" /> class.
-        /// </summary>
-        public GraphTraversal()
-            : this(new List<ITraversalStrategy>(), new Bytecode())
-        {
-        }
-
-        /// <summary>
-        ///     Initializes a new instance of the <see cref="GraphTraversal{SType, EType}" /> class.
-        /// </summary>
-        /// <param name="traversalStrategies">The traversal strategies to be used by this graph traversal at evaluation time.</param>
-        /// <param name="bytecode">The <see cref="Bytecode" /> associated with the construction of this graph traversal.</param>
-        public GraphTraversal(ICollection<ITraversalStrategy> traversalStrategies, Bytecode bytecode)
-        {
-            TraversalStrategies = traversalStrategies;
-            Bytecode = bytecode;
-        }
-
-        private static GraphTraversal<S2, E2> Wrap<S2, E2>(GraphTraversal<S, E> traversal)
-        {
-            if (typeof(S2) == typeof(S) && typeof(E2) == typeof(E))
-            {
-                return traversal as GraphTraversal<S2, E2>;
-            }
-            // New wrapper
-            return new GraphTraversal<S2, E2>(traversal.TraversalStrategies, traversal.Bytecode);
-        }
-
-<% graphStepMethods.each { method -> %>
-        /// <summary>
-        ///     Adds the <%= method.methodName %> step to this <see cref="GraphTraversal{SType, EType}" />.
-        /// </summary>
-        public GraphTraversal<$method.t1, $method.t2> <%= toCSharpMethodName.call(method.methodName) %><%= method.tParam %> (<%= method.parameters %>)
-        {
-        <%  if (method.parameters.contains("params ")) {
-      %>    var args = new List<object>(<%= method.paramNames.init().size() %> + <%= method.paramNames.last() %>.Length) {<%= method.paramNames.init().join(", ") %>};
-            args.AddRange(<%= method.paramNames.last() %><% if (method.isArgsCastNecessary) { %>.Cast<object>()<% } %>);
-            Bytecode.AddStep("<%= method.methodName %>", args.ToArray());<%
-            }
-            else {
-      %>    Bytecode.AddStep("<%= method.methodName %>"<% if (method.parameters) out << ', '+ method.paramNames.join(", ") %>);<%
-            }
-        %>
-            return Wrap<$method.t1, $method.t2>(this);
-        }
-<% } %>
-
-        /// <summary>
-        /// Make a copy of a traversal that is reset for iteration.
-        /// </summary>
-        public GraphTraversal<S, E> Clone()
-        {
-            return new GraphTraversal<S, E>(TraversalStrategies, new Bytecode(Bytecode));
-        }
-    }
-}
\ No newline at end of file
diff --git a/gremlin-dotnet/glv/GraphTraversalSource.template b/gremlin-dotnet/glv/GraphTraversalSource.template
deleted file mode 100644
index 4ccf77f..0000000
--- a/gremlin-dotnet/glv/GraphTraversalSource.template
+++ /dev/null
@@ -1,173 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using Gremlin.Net.Process.Remote;
-using Gremlin.Net.Process.Traversal.Strategy.Decoration;
-using Gremlin.Net.Structure;
-
-// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml
-namespace Gremlin.Net.Process.Traversal
-{
-#pragma warning disable 1591
-
-    /// <summary>
-    ///     A <see cref="GraphTraversalSource" /> is the primary DSL of the Gremlin traversal machine.
-    ///     It provides access to all the configurations and steps for Turing complete graph computing.
-    /// </summary>
-    public class GraphTraversalSource
-    {
-        /// <summary>
-        ///     Gets or sets the traversal strategies associated with this graph traversal source.
-        /// </summary>
-        public ICollection<ITraversalStrategy> TraversalStrategies { get; set; }
-
-        /// <summary>
-        ///     Gets or sets the <see cref="Traversal.Bytecode" /> associated with the current state of this graph traversal
-        ///     source.
-        /// </summary>
-        public Bytecode Bytecode { get; set; }
-
-        /// <summary>
-        ///     Initializes a new instance of the <see cref="GraphTraversalSource" /> class.
-        /// </summary>
-        public GraphTraversalSource()
-            : this(new List<ITraversalStrategy>(), new Bytecode())
-        {
-        }
-
-        /// <summary>
-        ///     Initializes a new instance of the <see cref="GraphTraversalSource" /> class.
-        /// </summary>
-        /// <param name="traversalStrategies">The traversal strategies associated with this graph traversal source.</param>
-        /// <param name="bytecode">
-        ///     The <see cref="Traversal.Bytecode" /> associated with the current state of this graph traversal
-        ///     source.
-        /// </param>
-        public GraphTraversalSource(ICollection<ITraversalStrategy> traversalStrategies, Bytecode bytecode)
-        {
-            TraversalStrategies = traversalStrategies;
-            Bytecode = bytecode;
-        }
-
-        public GraphTraversalSource With(string key)
-        {
-            return With(key, true);
-        }
-
-        public GraphTraversalSource With(string key, object value)
-        {
-            var optionsStrategyInst = Bytecode.SourceInstructions.Find(
-                inst => inst.OperatorName == "withStrategies" && inst.Arguments[0] is OptionsStrategy);
-            OptionsStrategy optionsStrategy;
-
-            if (optionsStrategyInst == null)
-            {
-                optionsStrategy = new OptionsStrategy();
-                optionsStrategy.Configuration[key] = value;
-                return WithStrategies(optionsStrategy);
-            }
-
-            optionsStrategy = optionsStrategyInst.Arguments[0];
-            optionsStrategy.Configuration[key] = value;
-            return new GraphTraversalSource(new List<ITraversalStrategy>(TraversalStrategies),
-                new Bytecode(Bytecode));
-        }
-
-<% sourceStepMethods.each{ method -> %>
-        public GraphTraversalSource <%= toCSharpMethodName.call(method.methodName) %>(<%= method.parameters %>)
-        {
-            var source = new GraphTraversalSource(new List<ITraversalStrategy>(TraversalStrategies),
-                                                  new Bytecode(Bytecode));
-            <%  if (method.parameters.contains("params ")) {
-          %>var args = new List<object>(<%= method.paramNames.init().size() %> + <%= method.paramNames.last() %>.Length) {<%= method.paramNames.init().join(", ") %>};
-            args.AddRange(<%= method.paramNames.last() %>);
-            source.Bytecode.AddSource("<%= method.methodName %>", args.ToArray());<%
-            }
-            else {
-          %>source.Bytecode.AddSource("<%= method.methodName %>"<% if (method.parameters) out << ', '+ method.paramNames.join(", ") %>);<%
-            }
-        %>
-            return source;
-        }
-<% } %>
-        [Obsolete("Use the Bindings class instead.", false)]
-        public GraphTraversalSource WithBindings(object bindings)
-        {
-            return this;
-        }
-
-        /// <summary>
-        ///     Configures the <see cref="GraphTraversalSource" /> as a "remote" to issue the
-        ///     <see cref="GraphTraversal{SType, EType}" /> for execution elsewhere.
-        /// </summary>
-        /// <param name="remoteConnection">
-        ///     The <see cref="IRemoteConnection" /> instance to use to submit the
-        ///     <see cref="GraphTraversal{SType, EType}" />.
-        /// </param>
-        /// <returns>A <see cref="GraphTraversalSource" /> configured to use the provided <see cref="IRemoteConnection" />.</returns>
-        public GraphTraversalSource WithRemote(IRemoteConnection remoteConnection)
-        {
-            var source = new GraphTraversalSource(new List<ITraversalStrategy>(TraversalStrategies),
-                new Bytecode(Bytecode));
-            source.TraversalStrategies.Add(new RemoteStrategy(remoteConnection));
-            return source;
-        }
-
-        /// <summary>
-        ///     Add a GraphComputer class used to execute the traversal.
-        ///     This adds a <see cref="VertexProgramStrategy" /> to the strategies.
-        /// </summary>
-        public GraphTraversalSource WithComputer(string graphComputer = null, int? workers = null, string persist = null,
-            string result = null, ITraversal vertices = null, ITraversal edges = null,
-            Dictionary<string, dynamic> configuration = null)
-        {
-            return WithStrategies(new VertexProgramStrategy(graphComputer, workers, persist, result, vertices, edges, configuration));
-        }
-
-<% sourceSpawnMethods.each { method -> %>
-        /// <summary>
-        ///     Spawns a <see cref="GraphTraversal{SType, EType}" /> off this graph traversal source and adds the <%= method.methodName %> step to that
-        ///     traversal.
-        /// </summary>
-        public GraphTraversal<$method.t1, $method.t2> <%= toCSharpMethodName.call(method.methodName) %><%= method.tParam %>(<%= method.parameters %>)
-        {
-            var traversal = new GraphTraversal<$method.t1, $method.t2>(TraversalStrategies, new Bytecode(Bytecode));
-            <%  if (method.parameters.contains("params ")) {
-          %>var args = new List<object>(<%= method.paramNames.init().size() %> + <%= method.paramNames.last() %>.Length) {<%= method.paramNames.init().join(", ") %>};
-            args.AddRange(<%= method.paramNames.last() %><% if (method.isArgsCastNecessary) { %>.Cast<object>()<% } %>);
-            traversal.Bytecode.AddStep("<%= method.methodName %>", args.ToArray());<%
-            }
-            else {
-      %>    traversal.Bytecode.AddStep("<%= method.methodName %>"<% if (method.parameters) out << ', '+ method.paramNames.join(", ") %>);<%
-            }
-        %>
-            return traversal;
-        }
-<% } %>
-    }
-    
-#pragma warning restore 1591
-}
\ No newline at end of file
diff --git a/gremlin-dotnet/glv/Gremlin.Net.Template.csproj.template b/gremlin-dotnet/glv/Gremlin.Net.Template.csproj.template
deleted file mode 100644
index 3f694f6..0000000
--- a/gremlin-dotnet/glv/Gremlin.Net.Template.csproj.template
+++ /dev/null
@@ -1,32 +0,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.
--->
-
-<!--  THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml -->
-<Project Sdk="Microsoft.NET.Sdk">
-
-  <PropertyGroup>
-    <OutputType>Exe</OutputType>
-    <TargetFramework>netcoreapp3.1</TargetFramework>
-  </PropertyGroup>
-
-  <ItemGroup>
-    <!-- We need both reference elements until this is resolved: https://github.com/dotnet/sdk/issues/1151 -->
-    <ProjectReference Include="../Gremlin.Net/Gremlin.Net.csproj" />
-    <PackageReference Include="Gremlin.Net" Version="$projectVersion" />
-  </ItemGroup>
-
-</Project>
diff --git a/gremlin-dotnet/glv/Gremlin.Net.Template.nuspec.template b/gremlin-dotnet/glv/Gremlin.Net.Template.nuspec.template
deleted file mode 100644
index d77663b..0000000
--- a/gremlin-dotnet/glv/Gremlin.Net.Template.nuspec.template
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
-    <metadata>
-        <id>Gremlin.Net.Template</id>
-        <title>Gremlin.Net Template</title>
-        <version>$projectVersion</version>
-        <description>Gremlin.Net template to create a console application with dotnet new.</description>
-        <authors>Apache TinkerPop</authors>
-        <license type="expression">Apache-2.0</license>
-        <projectUrl>http://tinkerpop.apache.org</projectUrl>
-        <tags>TinkerPop Gremlin Gremlin.Net</tags>
-        <packageTypes>
-            <packageType name="Template" />
-        </packageTypes>
-    </metadata>
-    <files>
-        <file src=".template.config/template.json" target="content/.template.config" />
-        <file src="Gremlin.Net.Template.csproj" target="content" />
-        <file src="*.cs" target="content" />
-        <file src="../../LICENSE" target="LICENSE"/>
-        <file src="../../NOTICE" target="NOTICE"/>
-    </files>
-</package>
\ No newline at end of file
diff --git a/gremlin-dotnet/glv/Gremlin.Net.csproj.template b/gremlin-dotnet/glv/Gremlin.Net.csproj.template
deleted file mode 100644
index 1799a5a..0000000
--- a/gremlin-dotnet/glv/Gremlin.Net.csproj.template
+++ /dev/null
@@ -1,92 +0,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.
--->
-
-<!--  THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml -->
-<Project Sdk="Microsoft.NET.Sdk">
-
-  <PropertyGroup Label="Build">
-    <TargetFrameworks>netstandard1.3;netstandard2.0</TargetFrameworks>
-    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
-    <GenerateDocumentationFile>true</GenerateDocumentationFile>
-  </PropertyGroup>
-
-  <PropertyGroup Label="Package">
-    <Version>$projectVersion</Version>
-    <FileVersion><%= (projectVersion =~ /(\d+\.\d+\.\d+).*/)[0][1] %>.0</FileVersion>
-    <AssemblyVersion><%= (projectVersion =~ /(\d+\.\d+)\.*/)[0][1] %>.0.0</AssemblyVersion>
-    <Title>Gremlin.Net</Title>
-    <Authors>Apache TinkerPop</Authors>
-    <Description>Gremlin.Net for Apache TinkerPop™ is a language variant and driver for .NET.
-
-Apache TinkerPop™ is a graph computing framework for both graph databases (OLTP) and graph analytic systems (OLAP). Gremlin is the graph traversal language of TinkerPop. It can be described as a functional, data-flow language that enables users to succinctly express complex traversals on (or queries of) their application's property graph.
-
-Gremlin.Net implements Gremlin within .NET. C# syntax has the same constructs as Java including "dot notation" for function chaining (a.b.c), round bracket function arguments (a(b,c)), and support for global namespaces (a(b()) vs a(__.b())). As such, anyone familiar with Gremlin-Java will immediately be able to work with Gremlin.Net. Moreover, there are a few added constructs to Gremlin.Net that make traversals a bit more succinct.
-
-Gremlin.Net is designed to connect to a "server" that is hosting a TinkerPop-enabled graph system. That "server" could be Gremlin Server
-
-https://tinkerpop.apache.org/docs/current/reference/#gremlin-server
-
-or a remote graph provider that exposes protocols by which Gremlin.Net can connect.
-
-Please see the Reference Documentation of Apache TinkerPop for more information on usage: https://tinkerpop.apache.org/docs/current/reference
-
-and use our Google Group gremlin-users if there are any questions: https://s.apache.org/c8hru
-
-The Gremlin language allows users to write highly expressive graph traversals and has a broad list of functions that cover a wide body of features. The Reference Documentation describes these functions and other aspects of the TinkerPop ecosystem including some specifics on Gremlin in .NET itself:
-
-https://s.apache.org/pgbwu
-
-Most of the examples found in the documentation use Groovy language syntax in the Gremlin Console. For the most part, these examples should generally translate to C# with some logical modification:
-
-https://s.apache.org/10v91
-
-Given the strong correspondence between canonical Gremlin in Java and its variants like C#, there is a limited amount of C#-specific documentation and examples. This strong correspondence among variants ensures that the general Gremlin reference documentation is applicable to all variants and that users moving between development languages can easily adopt the Gremlin variant for that language.
-
-NOTE that versions suffixed with "-rc" are considered release candidates (i.e. pre-alpha, alpha, beta, etc.) and thus for early testing purposes only.</Description>
-    <AssemblyOriginatorKeyFile>../../build/tinkerpop.snk</AssemblyOriginatorKeyFile>
-    <SignAssembly>true</SignAssembly>
-    <PackageId>Gremlin.Net</PackageId>
-    <PackageTags>gremlin;tinkerpop;apache</PackageTags>
-    <PackageProjectUrl>https://tinkerpop.apache.org</PackageProjectUrl>
-    <PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
-    <PackageIcon>gremlin-dotnet-logo_256x256.png</PackageIcon>
-    <PackageIconUrl>https://tinkerpop.apache.org/docs/current/images/gremlin-dotnet-logo_256x256.png</PackageIconUrl>
-    <RepositoryUrl>https://github.com/apache/tinkerpop</RepositoryUrl>
-    <PublishRepositoryUrl>true</PublishRepositoryUrl>    
-    <AllowedOutputExtensionsInPackageBuildOutputFolder>\$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
-  </PropertyGroup>
-
-  <ItemGroup>
-    <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
-    <PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
-    <PackageReference Include="Microsoft.CSharp" Version="4.3.0" />
-    <PackageReference Include="Polly" Version="7.2.0" />
-  </ItemGroup>
-
-  <ItemGroup Condition="'\$(TargetFramework)' == 'netstandard1.3'">
-    <PackageReference Include="System.Net.WebSockets" Version="4.3.0" />
-    <PackageReference Include="System.Net.WebSockets.Client" Version="4.3.2" />
-    <PackageReference Include="System.Reflection.TypeExtensions" Version="4.3.0" />
-  </ItemGroup>
-
-  <ItemGroup>
-    <None Include="../../LICENSE" Pack="true" PackagePath="" />
-    <None Include="../../NOTICE" Pack="true" PackagePath="" />
-    <None Include="../../../docs/static/images/gremlin-dotnet-logo_256x256.png" Pack="true" PackagePath="" />
-  </ItemGroup>
-
-</Project>
diff --git a/gremlin-dotnet/glv/P.template b/gremlin-dotnet/glv/P.template
deleted file mode 100644
index 3140475..0000000
--- a/gremlin-dotnet/glv/P.template
+++ /dev/null
@@ -1,113 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml
-using System.Collections;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace Gremlin.Net.Process.Traversal
-{
-#pragma warning disable 1591
-
-    /// <summary>
-    ///     A <see cref="P" /> is a predicate of the form Func&lt;object, bool&gt;.
-    ///     That is, given some object, return true or false.
-    /// </summary>
-    public class P : IPredicate
-    {
-        /// <summary>
-        ///     Initializes a new instance of the <see cref="P" /> class.
-        /// </summary>
-        /// <param name="operatorName">The name of the predicate.</param>
-        /// <param name="value">The value of the predicate.</param>
-        /// <param name="other">An optional other predicate that is used as an argument for this predicate.</param>
-        public P(string operatorName, dynamic value, P other = null)
-        {
-            OperatorName = operatorName;
-            Value = value;
-            Other = other;
-        }
-
-        /// <summary>
-        ///     Gets the name of the predicate.
-        /// </summary>
-        public string OperatorName { get; }
-
-        /// <summary>
-        ///     Gets the value of the predicate.
-        /// </summary>
-        public dynamic Value { get; }
-
-        /// <summary>
-        ///     Gets an optional other predicate that is used as an argument for this predicate.
-        /// </summary>
-        public P Other { get; }
-
-        /// <summary>
-        ///     Returns a composed predicate that represents a logical AND of this predicate and another.
-        /// </summary>
-        /// <param name="otherPredicate">A predicate that will be logically-ANDed with this predicate.</param>
-        /// <returns>The composed predicate.</returns>
-        public P And(P otherPredicate)
-        {
-            return new P("and", this, otherPredicate);
-        }
-
-        /// <summary>
-        ///     Returns a composed predicate that represents a logical OR of this predicate and another.
-        /// </summary>
-        /// <param name="otherPredicate">A predicate that will be logically-ORed with this predicate.</param>
-        /// <returns>The composed predicate.</returns>
-        public P Or(P otherPredicate)
-        {
-            return new P("or", this, otherPredicate);
-        }
-<% pmethods.findAll{ !(it in ["within", "without"]) }.each { method -> %>
-        public static P <%= toCSharpMethodName.call(method) %>(params object[] args)
-        {
-            var value = args.Length == 1 ? args[0] : args;
-            return new P("<%= method %>", value);
-        }
-<% } %><% pmethods.findAll{ it in ["within", "without"] }.each { method -> %>
-        public static P <%= toCSharpMethodName.call(method) %>(params object[] args)
-        {
-            var x = args.Length == 1 && args[0] is ICollection collection ? collection : args;
-            return new P("<%= method %>", ToGenericList(x));
-        }
-<% } %>
-
-        private static List<object> ToGenericList(IEnumerable collection)
-        {
-            return collection?.Cast<object>().ToList() ?? Enumerable.Empty<object>().ToList();
-        }
-
-        /// <inheritdoc />
-        public override string ToString()
-        {
-            return Other == null ? \$"{OperatorName}({Value})" : \$"{OperatorName}({Value},{Other})";
-        }
-    }
-
-#pragma warning restore 1591
-}
\ No newline at end of file
diff --git a/gremlin-dotnet/glv/TextP.template b/gremlin-dotnet/glv/TextP.template
deleted file mode 100644
index 3e289f6..0000000
--- a/gremlin-dotnet/glv/TextP.template
+++ /dev/null
@@ -1,71 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Linq;
-using System.Reflection;
-
-namespace Gremlin.Net.Process.Traversal
-{
-#pragma warning disable 1591
-
-    /// <summary>
-    ///     A <see cref="TextP" /> is a predicate of the form Func&lt;string, bool&gt;.
-    ///     That is, given some string, return true or false.
-    /// </summary>
-    public class TextP : P
-    {
-        /// <summary>
-        ///     Initializes a new instance of the <see cref="TextP" /> class.
-        /// </summary>
-        /// <param name="operatorName">The name of the predicate.</param>
-        /// <param name="value">The value of the predicate.</param>
-        /// <param name="other">An optional other predicate that is used as an argument for this predicate.</param>
-        public TextP(string operatorName, string value, P other = null) : base(operatorName, value, other)
-        {
-        }
-
-<% tpmethods.each { method -> %>
-        public static TextP <%= toCSharpMethodName.call(method) %>(string value)
-        {
-            return new TextP("<%= method %>", value);
-        }
-<% } %>
-
-        private static T[] ToGenericArray<T>(ICollection<T> collection)
-        {
-            return collection?.ToArray() ?? new T[0];
-        }
-
-        /// <inheritdoc />
-        public override string ToString()
-        {
-            return Other == null ? \$"{OperatorName}({Value})" : \$"{OperatorName}({Value},{Other})";
-        }
-    }
-
-#pragma warning restore 1591
-}
diff --git a/gremlin-dotnet/glv/Token.template b/gremlin-dotnet/glv/Token.template
deleted file mode 100644
index b86634a..0000000
--- a/gremlin-dotnet/glv/Token.template
+++ /dev/null
@@ -1,43 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Linq;
-using System.Reflection;
-
-namespace Gremlin.Net.Process.Traversal
-{
-#pragma warning disable 1591
-
-    public class <%= tokenName %>
-    {
-        <% tokenFields.each {k,v -> %>
-            public const String <%= k %> = "<%= v %>";
-        <% } %>
-    }
-
-#pragma warning restore 1591
-}
\ No newline at end of file
diff --git a/gremlin-dotnet/glv/WithOptions.template b/gremlin-dotnet/glv/WithOptions.template
deleted file mode 100644
index d8dd6bd..0000000
--- a/gremlin-dotnet/glv/WithOptions.template
+++ /dev/null
@@ -1,47 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Linq;
-using System.Reflection;
-
-namespace Gremlin.Net.Process.Traversal.Step.Util
-{
-#pragma warning disable 1591
-
-    /// <summary>
-    ///     Configuration options to be passed to the <c>With()</c> modulator.
-    /// </summary>
-    public class WithOptions
-    {
-<% withOptions.each { field -> %>
-
-        public static readonly <%= field.type %> <%= field.name %> = <%= field.value %>;
-<% } %>
-    }
-
-#pragma warning restore 1591
-}
diff --git a/gremlin-dotnet/glv/generate.groovy b/gremlin-dotnet/glv/generate.groovy
deleted file mode 100644
index a921a29..0000000
--- a/gremlin-dotnet/glv/generate.groovy
+++ /dev/null
@@ -1,407 +0,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.
- */
-
-import org.apache.tinkerpop.gremlin.jsr223.CoreImports
-import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.ConnectedComponent
-import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.PageRank
-import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.PeerPressure
-import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.ShortestPath
-import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource
-import org.apache.tinkerpop.gremlin.process.traversal.P
-import org.apache.tinkerpop.gremlin.process.traversal.TextP
-import org.apache.tinkerpop.gremlin.process.traversal.IO
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.WithOptions
-import org.apache.tinkerpop.gremlin.structure.Direction
-import java.lang.reflect.Modifier
-import java.lang.reflect.TypeVariable
-import java.lang.reflect.GenericArrayType
-
-def toCSharpTypeMap = ["Long": "long",
-                       "Double": "double",
-                       "Integer": "int",
-                       "String": "string",
-                       "boolean": "bool",
-                       "Object": "object",
-                       "String[]": "string[]",
-                       "Object[]": "object[]",
-                       "Class": "Type",
-                       "Class[]": "Type[]",
-                       "java.util.Map<java.lang.String, java.lang.Object>": "IDictionary<string, object>",
-                       "java.util.Map<java.lang.String, E2>": "IDictionary<string, E2>",
-                       "java.util.Map<java.lang.String, B>": "IDictionary<string, E2>",
-                       "java.util.Map<java.lang.Object, E2>": "IDictionary<object, E2>",
-                       "java.util.Map<java.lang.Object, B>": "IDictionary<object, E2>",
-                       "java.util.List<E>": "IList<E>",
-                       "java.util.List<A>": "IList<E2>",
-                       "java.util.Map<K, V>": "IDictionary<K, V>",
-                       "java.util.Collection<E2>": "ICollection<E2>",
-                       "java.util.Collection<B>": "ICollection<E2>",
-                       "java.util.Map<K, java.lang.Long>": "IDictionary<K, long>",
-                       "TraversalMetrics": "E2",
-                       "Traversal": "ITraversal",
-                       "Traversal[]": "ITraversal[]",
-                       "Predicate": "IPredicate",
-                       "P": "P",
-                       "TextP": "TextP",
-                       "TraversalStrategy": "ITraversalStrategy",
-                       "TraversalStrategy[]": "ITraversalStrategy[]",
-                       "Function": "IFunction",
-                       "BiFunction": "IBiFunction",
-                       "UnaryOperator": "IUnaryOperator",
-                       "BinaryOperator": "IBinaryOperator",
-                       "Consumer": "IConsumer",
-                       "Supplier": "ISupplier",
-                       "Comparator": "IComparator",
-                       "VertexProgram": "object"]
-
-def useE2 = ["E2", "E2"]
-def methodsWithSpecificTypes = ["constant": useE2,
-                                "limit": useE2,
-                                "mean": useE2,
-                                "optional": useE2,
-                                "range": useE2,
-                                "skip": useE2,
-                                "sum": useE2,
-                                "tail": useE2,
-                                "unfold": useE2,
-                                "valueMap": ["IDictionary<TKey, TValue>", "TKey, TValue"],]
-
-def getCSharpGenericTypeParam = { typeName ->
-    def tParam = ""
-    if (typeName.contains("E2")) {
-        tParam = "<E2>"
-    }
-    else if (typeName.contains("<K, V>")) {
-        tParam = "<K, V>"
-    }
-    else if (typeName.contains("<K, ")) {
-        tParam = "<K>"
-    }
-    else if (typeName.contains("S")) {
-        tParam = "<S>"
-    }
-    else if (typeName.contains("A")) {
-        tParam = "<A>"
-    }
-    return tParam
-}
-
-def toCSharpType = { name ->
-    String typeName = toCSharpTypeMap.getOrDefault(name, name)
-    if (typeName == name && (typeName.contains("? extends") || typeName == "Tree")) {
-        typeName = "E2"
-    }
-    return typeName
-}
-
-def toCSharpMethodName = { symbol -> (String) Character.toUpperCase(symbol.charAt(0)) + symbol.substring(1) }
-
-def toCSharpValue = { type, value ->
-  type == String.class && value != null ? ('"' + value + '"') : value
-}
-
-def getJavaGenericTypeParameterTypeNames = { method ->
-    def typeArguments = method.genericReturnType.actualTypeArguments
-    return typeArguments.
-            collect { (it instanceof Class) ? ((Class)it).simpleName : it.typeName }.
-            collect { name ->
-                if (name == "A") {
-                    name = "object"
-                }
-                else if (name == "B") {
-                    name = "E2"
-                }
-                name
-            }
-}
-
-def getJavaParameterTypeNames = { method ->
-    return method.parameters.
-            collect { param ->
-                param.type.simpleName
-            }
-}
-
-def toCSharpParamString = { param, genTypeName ->
-    String csharpParamTypeName = genTypeName
-    if (csharpParamTypeName == null){
-        csharpParamTypeName = toCSharpType(param.type.simpleName)
-    }
-    else if (csharpParamTypeName == "M") {
-        csharpParamTypeName = "object"
-    }
-    else if (csharpParamTypeName == "A[]") {
-        csharpParamTypeName = "object[]"
-    }
-    else if (csharpParamTypeName == "A" || csharpParamTypeName == "B") {
-        csharpParamTypeName = "E2"
-    }
-    "${csharpParamTypeName} ${param.name}"
-    }
-
-def getJavaParamTypeString = { method ->
-    getJavaParameterTypeNames(method).join(",")
-}
-
-def getCSharpParamTypeString = { method ->
-    return method.parameters.
-            collect { param ->
-                toCSharpType(param.type.simpleName)
-            }.join(",")
-}
-
-def getCSharpParamString = { method, useGenericParams ->
-    def parameters = method.parameters
-    if (parameters.length == 0)
-        return ""
-
-    def genericTypes = method.getGenericParameterTypes()
-    def csharpParameters = parameters.
-            toList().indexed().
-            collect { index, param ->
-                String genTypeName = null
-                if (useGenericParams) {
-                    def genType = genericTypes[index]
-                    if (genType instanceof TypeVariable<?>) {
-                        genTypeName = ((TypeVariable<?>)genType).name
-                    }
-                    else if (genType instanceof GenericArrayType) {
-                        if (((GenericArrayType)genType).getGenericComponentType() instanceof TypeVariable<?>) {
-                            genTypeName = ((TypeVariable<?>)((GenericArrayType)genType).getGenericComponentType()).name + "[]"
-                        }
-                    }
-                }
-                toCSharpParamString(param, genTypeName)
-            }.
-            toArray()
-
-    if (method.isVarArgs()) {
-        def lastIndex = csharpParameters.length-1
-        csharpParameters[lastIndex] = "params " + csharpParameters[lastIndex]
-    }
-
-    csharpParameters.join(", ")
-}
-
-def getParamNames = { parameters ->
-    return parameters.
-        collect { param ->
-            param.name
-        }
-}
-
-def isParamsArgCastNecessary = { parameterString ->
-    if (parameterString.contains("params ")) {
-        def paramsType = parameterString.substring(parameterString.indexOf("params ") + "params ".length(), parameterString.indexOf("[]"))
-        return paramsType == "E" || paramsType == "S" 
-    }
-    return false
-}
-
-def hasMethodNoGenericCounterPartInGraphTraversal = { method ->
-    def parameterTypeNames = getJavaParameterTypeNames(method)
-    if (method.name.equals("fold")) {
-        return parameterTypeNames.size() == 0
-    }
-    return false
-}
-
-def t2withSpecialGraphTraversalt2 = ["IList<E2>": "E2"]
-
-def getGraphTraversalT2ForT2 = { t2 ->
-    if (t2withSpecialGraphTraversalt2.containsKey(t2)) {
-        return t2withSpecialGraphTraversalt2.get(t2)
-    }
-    return t2
-}
-
-def gatherTokensFrom = { tokenClasses ->
-    def m = [:]
-    tokenClasses.each { tc -> m << [(tc.simpleName) : tc.getFields().sort{ a, b -> a.name <=> b.name }.collectEntries{ f -> [(f.name) : f.get(null)]}]}
-    return m
-}
-
-def binding = ["pmethods": P.class.getMethods().
-        findAll { Modifier.isStatic(it.getModifiers()) }.
-        findAll { P.class.isAssignableFrom(it.returnType) }.
-        collect { it.name }.
-        unique().
-        sort { a, b -> a <=> b },
-               "tpmethods": TextP.class.getMethods().
-                       findAll { Modifier.isStatic(it.getModifiers()) }.
-                       findAll { TextP.class.isAssignableFrom(it.returnType) }.
-                       collect { it.name }.
-                       unique().
-                       sort { a, b -> a <=> b },
-               "sourceStepMethods": GraphTraversalSource.getMethods(). // SOURCE STEPS
-                        findAll { (GraphTraversalSource.class == it.returnType) }.
-                        findAll {
-                            it.name != "clone" &&
-                                    it.name != TraversalSource.Symbols.with &&
-                                    it.name != TraversalSource.Symbols.withRemote &&
-                                    it.name != TraversalSource.Symbols.withComputer
-                        }.
-                // Select unique combination of C# parameter types and sort by Java parameter type combination
-                        sort { a, b -> a.name <=> b.name ?: getJavaParamTypeString(a) <=> getJavaParamTypeString(b) }.
-                        unique { a,b -> a.name <=> b.name ?: getCSharpParamTypeString(a) <=> getCSharpParamTypeString(b) }.
-                        collect { javaMethod ->
-                            def parameters = getCSharpParamString(javaMethod, false)
-                            def paramNames = getParamNames(javaMethod.parameters)
-                            return ["methodName": javaMethod.name, "parameters":parameters, "paramNames":paramNames]
-                        },
-               "sourceSpawnMethods": GraphTraversalSource.getMethods(). // SPAWN STEPS
-                        findAll { (GraphTraversal.class == it.returnType) }.
-                // Select unique combination of C# parameter types and sort by Java parameter type combination
-                        sort { a, b -> a.name <=> b.name ?: getJavaParamTypeString(a) <=> getJavaParamTypeString(b) }.
-                        unique { a,b -> a.name <=> b.name ?: getCSharpParamTypeString(a) <=> getCSharpParamTypeString(b) }.
-                        collect { javaMethod ->
-                            def typeNames = getJavaGenericTypeParameterTypeNames(javaMethod)
-                            def t1 = toCSharpType(typeNames[0])
-                            def t2 = toCSharpType(typeNames[1])
-                            def tParam = getCSharpGenericTypeParam(t2)
-                            def parameters = getCSharpParamString(javaMethod, true)
-                            def paramNames = getParamNames(javaMethod.parameters)
-                            def isArgsCastNecessary = isParamsArgCastNecessary(parameters)
-                            return ["methodName": javaMethod.name, "t1":t1, "t2":t2, "tParam":tParam, "parameters":parameters, "paramNames":paramNames, "isArgsCastNecessary":isArgsCastNecessary]
-                        },
-               "graphStepMethods": GraphTraversal.getMethods().
-                        findAll { (GraphTraversal.class == it.returnType) }.
-                        findAll { it.name != "clone" && it.name != "iterate" }.
-                // Select unique combination of C# parameter types and sort by Java parameter type combination
-                        sort { a, b -> a.name <=> b.name ?: getJavaParamTypeString(a) <=> getJavaParamTypeString(b) }.
-                        unique { a,b -> a.name <=> b.name ?: getCSharpParamTypeString(a) <=> getCSharpParamTypeString(b) }.
-                        collect { javaMethod ->
-                            def typeNames = getJavaGenericTypeParameterTypeNames(javaMethod)
-                            def t1 = toCSharpType(typeNames[0])
-                            def t2 = toCSharpType(typeNames[1])
-                            def tParam = getCSharpGenericTypeParam(t2)
-                            def specificTypes = methodsWithSpecificTypes.get(javaMethod.name)
-                            if (specificTypes) {
-                                t2 = specificTypes[0]
-                                tParam = specificTypes.size() > 1 ? "<" + specificTypes[1] + ">" : ""
-                            }
-                            def parameters = getCSharpParamString(javaMethod, true)
-                            def paramNames = getParamNames(javaMethod.parameters)
-                            def isArgsCastNecessary = isParamsArgCastNecessary(parameters)
-                            return ["methodName": javaMethod.name, "t1":t1, "t2":t2, "tParam":tParam, "parameters":parameters, "paramNames":paramNames, "isArgsCastNecessary":isArgsCastNecessary]
-                        },
-               "anonStepMethods": __.class.getMethods().
-                        findAll { (GraphTraversal.class == it.returnType) }.
-                        findAll { Modifier.isStatic(it.getModifiers()) }.
-                        findAll { it.name != "__" && it.name != "start" }.
-                // Select unique combination of C# parameter types and sort by Java parameter type combination
-                        sort { a, b -> a.name <=> b.name ?: getJavaParamTypeString(a) <=> getJavaParamTypeString(b) }.
-                        unique { a,b -> a.name <=> b.name ?: getCSharpParamTypeString(a) <=> getCSharpParamTypeString(b) }.
-                        collect { javaMethod ->
-                            def typeNames = getJavaGenericTypeParameterTypeNames(javaMethod)
-                            def t2 = toCSharpType(typeNames[1])
-                            def tParam = getCSharpGenericTypeParam(t2)
-                            def specificTypes = methodsWithSpecificTypes.get(javaMethod.name)
-                            if (specificTypes) {
-                                t2 = specificTypes[0]
-                                tParam = specificTypes.size() > 1 ? "<" + specificTypes[1] + ">" : ""
-                            }
-                            def parameters = getCSharpParamString(javaMethod, true)
-                            def paramNames = getParamNames(javaMethod.parameters)
-                            def callGenericTypeArg = hasMethodNoGenericCounterPartInGraphTraversal(javaMethod) ? "" : tParam
-                            def graphTraversalT2 = getGraphTraversalT2ForT2(t2)
-                            return ["methodName": javaMethod.name, "t2":t2, "tParam":tParam, "parameters":parameters, "paramNames":paramNames, "callGenericTypeArg":callGenericTypeArg, "graphTraversalT2":graphTraversalT2]
-                        },
-               "tokens": gatherTokensFrom([IO, ConnectedComponent, ShortestPath, PageRank, PeerPressure]),
-               "toCSharpMethodName": toCSharpMethodName,
-               "withOptions": WithOptions.getDeclaredFields().
-                        collect {["type": toCSharpType(it.type.simpleName), "name": toCSharpMethodName(it.name), "value": toCSharpValue(it.type, it.get(null))]}]
-
-def engine = new groovy.text.GStringTemplateEngine()
-def traversalTemplate = engine.createTemplate(new File("${projectBaseDir}/glv/GraphTraversal.template")).make(binding)
-def traversalFile = new File("${projectBaseDir}/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs")
-traversalFile.newWriter().withWriter{ it << traversalTemplate }
-
-def graphTraversalTemplate = engine.createTemplate(new File("${projectBaseDir}/glv/GraphTraversalSource.template")).make(binding)
-def graphTraversalFile = new File("${projectBaseDir}/src/Gremlin.Net/Process/Traversal/GraphTraversalSource.cs")
-graphTraversalFile.newWriter().withWriter{ it << graphTraversalTemplate }
-
-def anonymousTraversalTemplate = engine.createTemplate(new File("${projectBaseDir}/glv/AnonymousTraversal.template")).make(binding)
-def anonymousTraversalFile = new File("${projectBaseDir}/src/Gremlin.Net/Process/Traversal/__.cs")
-anonymousTraversalFile.newWriter().withWriter{ it << anonymousTraversalTemplate }
-
-def pTemplate = engine.createTemplate(new File("${projectBaseDir}/glv/P.template")).make(binding)
-def pFile = new File("${projectBaseDir}/src/Gremlin.Net/Process/Traversal/P.cs")
-pFile.newWriter().withWriter{ it << pTemplate }
-
-def tpTemplate = engine.createTemplate(new File("${projectBaseDir}/glv/TextP.template")).make(binding)
-def tpFile = new File("${projectBaseDir}/src/Gremlin.Net/Process/Traversal/TextP.cs")
-tpFile.newWriter().withWriter{ it << tpTemplate }
-
-def withOptionsTemplate = engine.createTemplate(new File("${projectBaseDir}/glv/WithOptions.template")).make(binding)
-def withOptionsFile = new File("${projectBaseDir}/src/Gremlin.Net/Process/Traversal/WithOptions.cs")
-withOptionsFile.newWriter().withWriter{ it << withOptionsTemplate }
-
-binding.tokens.each {k,v ->
-    def tokenTemplate = engine.createTemplate(new File("${projectBaseDir}/glv/Token.template")).make([tokenFields: v, tokenName: k])
-    def tokenFile = new File("${projectBaseDir}/src/Gremlin.Net/Process/Traversal/${k}.cs")
-    tokenFile.newWriter().withWriter{ it << tokenTemplate }
-}
-
-def createEnum = { enumClass ->
-    def b = ["enumClass": enumClass,
-             "implementedTypes": enumClass.getInterfaces().
-                    collect { it.getSimpleName() }.
-                    findAll { toCSharpTypeMap.containsKey(it) }.
-                    findAll { toCSharpTypeMap[it] != "object" }.
-                    sort { a, b -> a <=> b }.
-                    collect(["EnumWrapper"]) { typeName ->
-                        return toCSharpTypeMap[typeName]
-                    }.join(", "),
-             "constants": enumClass.getEnumConstants().
-                    sort { a, b -> a.name() <=> b.name() },
-             "directionClass": Direction.class ]
-
-    def enumTemplate = engine.createTemplate(new File("${projectBaseDir}/glv/Enum.template")).make(b)
-    def enumFile = new File("${projectBaseDir}/src/Gremlin.Net/Process/Traversal/" + enumClass.getSimpleName() + ".cs")
-    enumFile.newWriter().withWriter{ it << enumTemplate }
-}
-
-CoreImports.getClassImports().findAll { Enum.class.isAssignableFrom(it) }.
-        sort { a, b -> a.getSimpleName() <=> b.getSimpleName() }.
-        each { createEnum(it) }
-
-def determineVersion = {
-    def env = System.getenv()
-    def mavenVersion = env.containsKey("TP_RELEASE_VERSION") ? env.get("DOTNET_RELEASE_VERSION") : "${projectVersion}"
-
-    // only want to generate a timestamp for the version if this is a nuget deploy
-    if (!mavenVersion.endsWith("-SNAPSHOT") || null == System.getProperty("nuget")) return mavenVersion
-
-    return mavenVersion.replace("-SNAPSHOT", "-dev-" + System.currentTimeMillis())
-}
-
-def versionToUse = determineVersion()
-def csprojTemplate = engine.createTemplate(new File("${projectBaseDir}/glv/Gremlin.Net.csproj.template")).make(["projectVersion":versionToUse])
-def csprojFile = new File("${projectBaseDir}/src/Gremlin.Net/Gremlin.Net.csproj")
-csprojFile.newWriter().withWriter{ it << csprojTemplate }
-def templateCsprojTemplate = engine.createTemplate(new File("${projectBaseDir}/glv/Gremlin.Net.Template.csproj.template")).make(["projectVersion":versionToUse])
-def templateCsprojFile = new File("${projectBaseDir}/src/Gremlin.Net.Template/Gremlin.Net.Template.csproj")
-templateCsprojFile.newWriter().withWriter{ it << templateCsprojTemplate }
-def nuspecTemplate = engine.createTemplate(new File("${projectBaseDir}/glv/Gremlin.Net.Template.nuspec.template")).make(["projectVersion":versionToUse])
-def nuspecFile = new File("${projectBaseDir}/src/Gremlin.Net.Template/Gremlin.Net.Template.nuspec")
-nuspecFile.newWriter().withWriter{ it << nuspecTemplate }
diff --git a/gremlin-dotnet/pom.xml b/gremlin-dotnet/pom.xml
index d8cedc1..44a30fa 100644
--- a/gremlin-dotnet/pom.xml
+++ b/gremlin-dotnet/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.apache.tinkerpop</groupId>
         <artifactId>tinkerpop</artifactId>
-        <version>3.4.12-SNAPSHOT</version>
+        <version>3.5.1-SNAPSHOT</version>
     </parent>
     <artifactId>gremlin-dotnet</artifactId>
     <name>Apache TinkerPop :: Gremlin.Net</name>
@@ -59,54 +59,6 @@
                 <artifactId>dotnet-maven-plugin</artifactId>
                 <extensions>true</extensions>
             </plugin>
-            <plugin>
-                <groupId>org.codehaus.gmavenplus</groupId>
-                <artifactId>gmavenplus-plugin</artifactId>
-                <dependencies>
-                    <dependency>
-                        <groupId>org.apache.tinkerpop</groupId>
-                        <artifactId>gremlin-server</artifactId>
-                        <version>${project.version}</version>
-                    </dependency>
-                    <dependency>
-                        <groupId>org.codehaus.groovy</groupId>
-                        <artifactId>groovy-all</artifactId>
-                        <version>${groovy.version}</version>
-                        <type>pom</type>
-                        <scope>runtime</scope>
-                    </dependency>
-                    <dependency>
-                        <groupId>log4j</groupId>
-                        <artifactId>log4j</artifactId>
-                        <version>${log4j.version}</version>
-                        <scope>runtime</scope>
-                    </dependency>
-                </dependencies>
-                <executions>
-                    <execution>
-                        <id>generate-dsl</id>
-                        <phase>generate-sources</phase>
-                        <goals>
-                            <goal>execute</goal>
-                        </goals>
-                        <configuration>
-                            <properties>
-                                <property>
-                                    <name>projectBaseDir</name>
-                                    <value>${project.basedir}</value>
-                                </property>
-                                <property>
-                                    <name>projectVersion</name>
-                                    <value>${project.version}</value>
-                                </property>
-                            </properties>
-                            <scripts>
-                                <script>${project.basedir}/glv/generate.groovy</script>
-                            </scripts>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
             <!--
             there is no point to deploying the jvm stuff - there is no java source really - just poms
             -->
diff --git a/gremlin-dotnet/src/Gremlin.Net.Template/Gremlin.Net.Template.csproj b/gremlin-dotnet/src/Gremlin.Net.Template/Gremlin.Net.Template.csproj
index 81abd44..dacce3f 100644
--- a/gremlin-dotnet/src/Gremlin.Net.Template/Gremlin.Net.Template.csproj
+++ b/gremlin-dotnet/src/Gremlin.Net.Template/Gremlin.Net.Template.csproj
@@ -15,7 +15,6 @@
 limitations under the License.
 -->
 
-<!--  THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml -->
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
@@ -26,7 +25,9 @@
   <ItemGroup>
     <!-- We need both reference elements until this is resolved: https://github.com/dotnet/sdk/issues/1151 -->
     <ProjectReference Include="../Gremlin.Net/Gremlin.Net.csproj" />
-    <PackageReference Include="Gremlin.Net" Version="3.4.12-SNAPSHOT" />
+
+    <!-- do not edit the version directly - maven updates it automatically -->
+    <PackageReference Include="Gremlin.Net" Version="3.5.1-SNAPSHOT" />
   </ItemGroup>
 
 </Project>
diff --git a/gremlin-dotnet/src/Gremlin.Net.Template/Gremlin.Net.Template.nuspec b/gremlin-dotnet/src/Gremlin.Net.Template/Gremlin.Net.Template.nuspec
index 8f0f27f..e3a0911 100644
--- a/gremlin-dotnet/src/Gremlin.Net.Template/Gremlin.Net.Template.nuspec
+++ b/gremlin-dotnet/src/Gremlin.Net.Template/Gremlin.Net.Template.nuspec
@@ -3,7 +3,10 @@
     <metadata>
         <id>Gremlin.Net.Template</id>
         <title>Gremlin.Net Template</title>
-        <version>3.4.12-SNAPSHOT</version>
+
+        <!-- do not edit the version directly - maven updates it automatically -->
+        <version>3.5.1-SNAPSHOT</version>
+
         <description>Gremlin.Net template to create a console application with dotnet new.</description>
         <authors>Apache TinkerPop</authors>
         <license type="expression">Apache-2.0</license>
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/Connection.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/Connection.cs
index 7436c3d..491a62a 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/Connection.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/Connection.cs
@@ -30,23 +30,19 @@
 using System.Threading.Tasks;
 using Gremlin.Net.Driver.Messages;
 using Gremlin.Net.Process;
-using Gremlin.Net.Structure.IO.GraphSON;
-using Newtonsoft.Json.Linq;
 
 namespace Gremlin.Net.Driver
 {
     internal interface IResponseHandlerForSingleRequestMessage
     {
-        void HandleReceived(ResponseMessage<JToken> received);
+        void HandleReceived(ResponseMessage<List<object>> received);
         void Finalize(Dictionary<string, object> statusAttributes);
         void HandleFailure(Exception objException);
     }
 
     internal class Connection : IConnection
     {
-        private readonly GraphSONReader _graphSONReader;
-        private readonly GraphSONWriter _graphSONWriter;
-        private readonly JsonMessageSerializer _messageSerializer;
+        private readonly IMessageSerializer _messageSerializer;
         private readonly Uri _uri;
         private readonly WebSocketConnection _webSocketConnection;
         private readonly string _username;
@@ -61,8 +57,7 @@
         private int _writeInProgress = 0;
         private const int Closed = 1;
 
-        public Connection(Uri uri, string username, string password, GraphSONReader graphSONReader,
-            GraphSONWriter graphSONWriter, string mimeType,
+        public Connection(Uri uri, string username, string password, IMessageSerializer messageSerializer,
             Action<ClientWebSocketOptions> webSocketConfiguration, string sessionId)
         {
             _uri = uri;
@@ -73,9 +68,7 @@
             {
                 _sessionEnabled = true;
             }
-            _graphSONReader = graphSONReader;
-            _graphSONWriter = graphSONWriter;
-            _messageSerializer = new JsonMessageSerializer(mimeType);
+            _messageSerializer = messageSerializer;
             _webSocketConnection = new WebSocketConnection(webSocketConfiguration);
         }
 
@@ -91,7 +84,7 @@
 
         public Task<ResultSet<T>> SubmitAsync<T>(RequestMessage requestMessage)
         {
-            var receiver = new ResponseHandlerForSingleRequestMessage<T>(_graphSONReader);
+            var receiver = new ResponseHandlerForSingleRequestMessage<T>();
             _callbackByRequestId.GetOrAdd(requestMessage.RequestId, receiver);
             _writeQueue.Enqueue(requestMessage);
             BeginSendingMessages();
@@ -112,7 +105,7 @@
                 try
                 {
                     var received = await _webSocketConnection.ReceiveMessageAsync().ConfigureAwait(false);
-                    Parse(received);
+                    await HandleReceivedAsync(received).ConfigureAwait(false);
                 }
                 catch (Exception e)
                 {
@@ -122,9 +115,9 @@
             }
         }
 
-        private void Parse(byte[] received)
+        private async Task HandleReceivedAsync(byte[] received)
         {
-            var receivedMsg = _messageSerializer.DeserializeMessage<ResponseMessage<JToken>>(received);
+            var receivedMsg = await _messageSerializer.DeserializeMessageAsync(received).ConfigureAwait(false);
             if (receivedMsg == null)
             {
                 ThrowMessageDeserializedNull();
@@ -132,11 +125,12 @@
 
             try
             {
-                TryParseResponseMessage(receivedMsg);
+                HandleReceivedMessage(receivedMsg);
             }
             catch (Exception e)
             {
-                if (_callbackByRequestId.TryRemove(receivedMsg.RequestId, out var responseHandler))
+                if (receivedMsg.RequestId != null &&
+                    _callbackByRequestId.TryRemove(receivedMsg.RequestId.Value, out var responseHandler))
                 {
                     responseHandler?.HandleFailure(e);
                 }
@@ -146,7 +140,7 @@
         private static void ThrowMessageDeserializedNull() =>
             throw new InvalidOperationException("Received data deserialized into null object message. Cannot operate on it.");
 
-        private void TryParseResponseMessage(ResponseMessage<JToken> receivedMsg)
+        private void HandleReceivedMessage(ResponseMessage<List<object>> receivedMsg)
         {
             var status = receivedMsg.Status;
             status.ThrowIfStatusIndicatesError();
@@ -157,13 +151,15 @@
                 return;
             }
 
+            if (receivedMsg.RequestId == null) return;
+
             if (status.Code != ResponseStatusCode.NoContent)
-                _callbackByRequestId[receivedMsg.RequestId].HandleReceived(receivedMsg);
+                _callbackByRequestId[receivedMsg.RequestId.Value].HandleReceived(receivedMsg);
 
             if (status.Code == ResponseStatusCode.Success || status.Code == ResponseStatusCode.NoContent)
             {
-                _callbackByRequestId[receivedMsg.RequestId].Finalize(status.Attributes);
-                _callbackByRequestId.TryRemove(receivedMsg.RequestId, out _);
+                _callbackByRequestId[receivedMsg.RequestId.Value].Finalize(status.Attributes);
+                _callbackByRequestId.TryRemove(receivedMsg.RequestId.Value, out _);
             }
         }
 
@@ -247,8 +243,7 @@
             {
                 message = RebuildSessionMessage(message);
             }
-            var graphsonMsg = _graphSONWriter.WriteObject(message);
-            var serializedMsg = _messageSerializer.SerializeMessage(graphsonMsg);
+            var serializedMsg = await _messageSerializer.SerializeMessageAsync(message).ConfigureAwait(false);
             await _webSocketConnection.SendMessageAsync(serializedMsg).ConfigureAwait(false);
         }
 
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/ConnectionFactory.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/ConnectionFactory.cs
index 9ef32a5..59807a1 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/ConnectionFactory.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/ConnectionFactory.cs
@@ -1,4 +1,4 @@
-#region License
+#region License
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -23,35 +23,29 @@
 
 using System;
 using System.Net.WebSockets;
-using Gremlin.Net.Structure.IO.GraphSON;
 
 namespace Gremlin.Net.Driver
 {
     internal class ConnectionFactory : IConnectionFactory
     {
-        private readonly GraphSONReader _graphSONReader;
-        private readonly GraphSONWriter _graphSONWriter;
         private readonly Action<ClientWebSocketOptions> _webSocketConfiguration;
         private readonly GremlinServer _gremlinServer;
-        private readonly string _mimeType;
         private readonly string _sessionId;
+        private IMessageSerializer _messageSerializer;
 
-        public ConnectionFactory(GremlinServer gremlinServer, GraphSONReader graphSONReader,
-            GraphSONWriter graphSONWriter, string mimeType,
+        public ConnectionFactory(GremlinServer gremlinServer, IMessageSerializer messageSerializer,
             Action<ClientWebSocketOptions> webSocketConfiguration, string sessionId)
         {
             _gremlinServer = gremlinServer;
-            _mimeType = mimeType;
+            _messageSerializer = messageSerializer;
             _sessionId = sessionId;
-            _graphSONReader = graphSONReader ?? throw new ArgumentNullException(nameof(graphSONReader));
-            _graphSONWriter = graphSONWriter ?? throw new ArgumentNullException(nameof(graphSONWriter));
             _webSocketConfiguration = webSocketConfiguration;
         }
 
         public IConnection CreateConnection()
         {
-            return new Connection(_gremlinServer.Uri, _gremlinServer.Username, _gremlinServer.Password, _graphSONReader,
-                                 _graphSONWriter, _mimeType, _webSocketConfiguration, _sessionId);
+            return new Connection(_gremlinServer.Uri, _gremlinServer.Username, _gremlinServer.Password,
+                _messageSerializer, _webSocketConfiguration, _sessionId);
         }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/GremlinClient.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/GremlinClient.cs
index bf637bf..745a3cc 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/GremlinClient.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/GremlinClient.cs
@@ -22,10 +22,10 @@
 #endregion
 
 using System;
-using System.Collections.Generic;
 using System.Net.WebSockets;
 using System.Threading.Tasks;
 using Gremlin.Net.Driver.Messages;
+using Gremlin.Net.Structure.IO;
 using Gremlin.Net.Structure.IO.GraphSON;
 
 namespace Gremlin.Net.Driver
@@ -35,16 +35,6 @@
     /// </summary>
     public class GremlinClient : IGremlinClient
     {
-        /// <summary>
-        /// Defines the default mime type to use.
-        /// </summary>
-        public const string DefaultMimeType = "application/vnd.gremlin-v3.0+json";
-
-        /// <summary>
-        /// The GraphSON2 mime type to use.
-        /// </summary>
-        public const string GraphSON2MimeType = "application/vnd.gremlin-v2.0+json";
-        
         private readonly ConnectionPool _connectionPool;
 
         /// <summary>
@@ -53,25 +43,69 @@
         /// <param name="gremlinServer">The <see cref="GremlinServer" /> the requests should be sent to.</param>
         /// <param name="graphSONReader">A <see cref="GraphSONReader" /> instance to read received GraphSON data.</param>
         /// <param name="graphSONWriter">a <see cref="GraphSONWriter" /> instance to write GraphSON data.</param>
-        /// <param name="mimeType">The GraphSON version mime type, defaults to latest supported by the server.</param>
-        /// <param name="connectionPoolSettings">The <see cref="ConnectionPoolSettings"/> for the connection pool.</param>
+        /// <param name="connectionPoolSettings">The <see cref="ConnectionPoolSettings" /> for the connection pool.</param>
         /// <param name="webSocketConfiguration">
         ///     A delegate that will be invoked with the <see cref="ClientWebSocketOptions" />
         ///     object used to configure WebSocket connections.
         /// </param>
         /// <param name="sessionId">The session Id if Gremlin Client in session mode, defaults to null as session-less Client.</param>
-        public GremlinClient(GremlinServer gremlinServer, GraphSONReader graphSONReader = null,
-            GraphSONWriter graphSONWriter = null, string mimeType = null,
+        [Obsolete("This constructor is obsolete. Use the constructor that takes a IMessageSerializer instead.")]
+        public GremlinClient(GremlinServer gremlinServer, GraphSONReader graphSONReader, GraphSONWriter graphSONWriter,
             ConnectionPoolSettings connectionPoolSettings = null,
             Action<ClientWebSocketOptions> webSocketConfiguration = null, string sessionId = null)
+            : this(gremlinServer, graphSONReader, graphSONWriter, SerializationTokens.GraphSON3MimeType,
+                connectionPoolSettings, webSocketConfiguration, sessionId)
         {
-            var reader = graphSONReader ?? new GraphSON3Reader();
-            var writer = graphSONWriter ?? new GraphSON3Writer();
-            var connectionFactory = new ConnectionFactory(gremlinServer, reader, writer, mimeType ?? DefaultMimeType,
-                webSocketConfiguration, sessionId);
+        }
+        
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="GremlinClient" /> class for the specified Gremlin Server.
+        /// </summary>
+        /// <param name="gremlinServer">The <see cref="GremlinServer" /> the requests should be sent to.</param>
+        /// <param name="graphSONReader">A <see cref="GraphSONReader" /> instance to read received GraphSON data.</param>
+        /// <param name="graphSONWriter">a <see cref="GraphSONWriter" /> instance to write GraphSON data.</param>
+        /// <param name="mimeType">The GraphSON version mime type, defaults to latest supported by the server.</param>
+        /// <param name="connectionPoolSettings">The <see cref="ConnectionPoolSettings" /> for the connection pool.</param>
+        /// <param name="webSocketConfiguration">
+        ///     A delegate that will be invoked with the <see cref="ClientWebSocketOptions" />
+        ///     object used to configure WebSocket connections.
+        /// </param>
+        /// <param name="sessionId">The session Id if Gremlin Client in session mode, defaults to null as session-less Client.</param>
+        [Obsolete("This constructor is obsolete. Use the constructor that takes a IMessageSerializer instead.")]
+        public GremlinClient(GremlinServer gremlinServer, GraphSONReader graphSONReader, GraphSONWriter graphSONWriter,
+            string mimeType, ConnectionPoolSettings connectionPoolSettings = null,
+            Action<ClientWebSocketOptions> webSocketConfiguration = null, string sessionId = null)
+        {
+            IMessageSerializer messageSerializer;
+            switch (mimeType)
+            {
+                case SerializationTokens.GraphSON3MimeType:
+                    VerifyGraphSONArgumentTypeForMimeType<GraphSON3Reader>(graphSONReader, nameof(graphSONReader),
+                        mimeType);
+                    VerifyGraphSONArgumentTypeForMimeType<GraphSON3Writer>(graphSONWriter, nameof(graphSONWriter),
+                        mimeType);
+                    messageSerializer = new GraphSON3MessageSerializer(
+                        (GraphSON3Reader) graphSONReader ?? new GraphSON3Reader(),
+                        (GraphSON3Writer) graphSONWriter ?? new GraphSON3Writer());
+                    break;
+                case SerializationTokens.GraphSON2MimeType:
+                    VerifyGraphSONArgumentTypeForMimeType<GraphSON2Reader>(graphSONReader, nameof(graphSONReader),
+                        mimeType);
+                    VerifyGraphSONArgumentTypeForMimeType<GraphSON2Writer>(graphSONWriter, nameof(graphSONWriter),
+                        mimeType);
+                    messageSerializer = new GraphSON2MessageSerializer(
+                        (GraphSON2Reader) graphSONReader ?? new GraphSON2Reader(),
+                        (GraphSON2Writer) graphSONWriter ?? new GraphSON2Writer());
+                    break;
+                default:
+                    throw new ArgumentException(nameof(mimeType), $"{mimeType} not supported");
+            }
+            
+            var connectionFactory =
+                new ConnectionFactory(gremlinServer, messageSerializer, webSocketConfiguration, sessionId);
 
             // make sure one connection in pool as session mode
-            if (!String.IsNullOrEmpty(sessionId))
+            if (!string.IsNullOrEmpty(sessionId))
             {
                 if (connectionPoolSettings != null)
                 {
@@ -80,12 +114,60 @@
                 }
                 else
                 {
-                    connectionPoolSettings = new ConnectionPoolSettings();
-                    connectionPoolSettings.PoolSize = 1;
+                    connectionPoolSettings = new ConnectionPoolSettings {PoolSize = 1};
                 }
             }
             _connectionPool =
-                new ConnectionPool(connectionFactory, connectionPoolSettings ?? new ConnectionPoolSettings());            
+                new ConnectionPool(connectionFactory, connectionPoolSettings ?? new ConnectionPoolSettings());
+        }
+
+        private static void VerifyGraphSONArgumentTypeForMimeType<T>(object argument, string argumentName,
+            string mimeType)
+        {
+            if (argument != null && !(argument is T))
+            {
+                throw new ArgumentException(
+                    $"{argumentName} is not a {typeof(T).Name} but the mime type is: {mimeType}", argumentName);
+            }
+        }
+
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="GremlinClient" /> class for the specified Gremlin Server.
+        /// </summary>
+        /// <param name="gremlinServer">The <see cref="GremlinServer" /> the requests should be sent to.</param>
+        /// <param name="messageSerializer">
+        ///     A <see cref="IMessageSerializer" /> instance to serialize messages sent to and received
+        ///     from the server.
+        /// </param>
+        /// <param name="connectionPoolSettings">The <see cref="ConnectionPoolSettings" /> for the connection pool.</param>
+        /// <param name="webSocketConfiguration">
+        ///     A delegate that will be invoked with the <see cref="ClientWebSocketOptions" />
+        ///     object used to configure WebSocket connections.
+        /// </param>
+        /// <param name="sessionId">The session Id if Gremlin Client in session mode, defaults to null as session-less Client.</param>
+        public GremlinClient(GremlinServer gremlinServer, IMessageSerializer messageSerializer = null,
+            ConnectionPoolSettings connectionPoolSettings = null,
+            Action<ClientWebSocketOptions> webSocketConfiguration = null, string sessionId = null)
+        {
+            messageSerializer = messageSerializer ?? new GraphSON3MessageSerializer();
+            var connectionFactory =
+                new ConnectionFactory(gremlinServer, messageSerializer, webSocketConfiguration, sessionId);
+
+            // make sure one connection in pool as session mode
+            if (!string.IsNullOrEmpty(sessionId))
+            {
+                if (connectionPoolSettings != null)
+                {
+                    if (connectionPoolSettings.PoolSize != 1)
+                        throw new ArgumentOutOfRangeException(nameof(connectionPoolSettings), "PoolSize must be 1 in session mode!");
+                }
+                else
+                {
+                    connectionPoolSettings = new ConnectionPoolSettings {PoolSize = 1};
+                }
+            }
+            _connectionPool =
+                new ConnectionPool(connectionFactory, connectionPoolSettings ?? new ConnectionPoolSettings());
         }
 
         /// <summary>
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/IMessageSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/IMessageSerializer.cs
new file mode 100644
index 0000000..22a8f9c
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/IMessageSerializer.cs
@@ -0,0 +1,49 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Gremlin.Net.Driver.Messages;
+
+namespace Gremlin.Net.Driver
+{
+    /// <summary>
+    ///     Serializes data to and from Gremlin Server.
+    /// </summary>
+    public interface IMessageSerializer
+    {
+        /// <summary>
+        ///     Serializes a <see cref="RequestMessage"/>.
+        /// </summary>
+        /// <param name="requestMessage">The <see cref="RequestMessage"/> to serialize.</param>
+        /// <returns>The serialized message.</returns>
+        Task<byte[]> SerializeMessageAsync(RequestMessage requestMessage);
+        
+        /// <summary>
+        ///     Deserializes a <see cref="ResponseMessage{T}"/> from a byte array.
+        /// </summary>
+        /// <param name="message">The serialized message to deserialize.</param>
+        /// <returns>The deserialized <see cref="ResponseMessage{T}"/>.</returns>
+        Task<ResponseMessage<List<object>>> DeserializeMessageAsync(byte[] message);
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/JsonMessageSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/JsonMessageSerializer.cs
deleted file mode 100644
index 53a546c..0000000
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/JsonMessageSerializer.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-using System.Text;
-using Newtonsoft.Json;
-
-namespace Gremlin.Net.Driver
-{
-    internal class JsonMessageSerializer
-    {
-        private readonly string _mimeType;
-
-        public JsonMessageSerializer(string mimeType)
-        {
-            _mimeType = mimeType;
-        }
-
-        public byte[] SerializeMessage(string msg)
-        {
-            return Encoding.UTF8.GetBytes(MessageWithHeader(msg));
-        }
-
-        private string MessageWithHeader(string messageContent)
-        {
-            return $"{(char) _mimeType.Length}{_mimeType}{messageContent}";
-        }
-
-        public TMessage DeserializeMessage<TMessage>(byte[] message)
-        {
-            var responseStr = Encoding.UTF8.GetString(message);
-            return JsonConvert.DeserializeObject<TMessage>(responseStr);
-        }
-    }
-}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/ResponseMessage.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/ResponseMessage.cs
index f1cb3ad..a273cc0 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/ResponseMessage.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/ResponseMessage.cs
@@ -22,19 +22,28 @@
 #endregion
 
 using System;
-using Newtonsoft.Json;
 
 namespace Gremlin.Net.Driver.Messages
 {
-    internal class ResponseMessage<T>
+    /// <summary>
+    ///     The message returned from the server.
+    /// </summary>
+    /// <typeparam name="T">The type of the data returned.</typeparam>
+    public class ResponseMessage<T>
     {
-        [JsonProperty(PropertyName = "requestId")]
-        public Guid RequestId { get; set; }
+        /// <summary>
+        ///     Gets or sets the identifier of the <see cref="RequestMessage"/> that generated this <see cref="ResponseMessage{T}"/>.
+        /// </summary>
+        public Guid? RequestId { get; set; }
 
-        [JsonProperty(PropertyName = "status")]
+        /// <summary>
+        ///     Gets or sets status information about this <see cref="ResponseMessage{T}"/>.
+        /// </summary>
         public ResponseStatus Status { get; set; }
 
-        [JsonProperty(PropertyName = "result")]
-        public ResponseResult Result { get; set; }
+        /// <summary>
+        ///     Gets or sets the result with its data and optional meta information.
+        /// </summary>
+        public ResponseResult<T> Result { get; set; }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/ResponseResult.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/ResponseResult.cs
index 848473b..abc2907 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/ResponseResult.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/ResponseResult.cs
@@ -22,17 +22,24 @@
 #endregion
 
 using System.Collections.Generic;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
 
 namespace Gremlin.Net.Driver.Messages
 {
-    internal class ResponseResult
+    /// <summary>
+    ///     Represents the result as a response to a <see cref="RequestMessage"/> sent as part of a
+    ///     <see cref="ResponseMessage{T}"/> by the server.
+    /// </summary>
+    /// <typeparam name="T">The type of the <see cref="Data"/>.</typeparam>
+    public class ResponseResult<T>
     {
-        [JsonProperty(PropertyName = "data")]
-        public JToken Data { get; set; }
+        /// <summary>
+        ///     Gets or sets the data of this result.
+        /// </summary>
+        public T Data { get; set; }
 
-        [JsonProperty(PropertyName = "meta")]
+        /// <summary>
+        ///     Gets or sets meta data of this result.
+        /// </summary>
         public Dictionary<string, object> Meta { get; set; }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/ResponseStatus.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/ResponseStatus.cs
index aa0b1b7..63530a3 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/ResponseStatus.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/ResponseStatus.cs
@@ -23,19 +23,27 @@
 
 using System.Collections.Generic;
 using Gremlin.Net.Driver.Exceptions;
-using Newtonsoft.Json;
 
 namespace Gremlin.Net.Driver.Messages
 {
-    internal class ResponseStatus
+    /// <summary>
+    ///     Represents status information of a <see cref="ResponseMessage{T}"/>.
+    /// </summary>
+    public class ResponseStatus
     {
-        [JsonProperty(PropertyName = "code")]
+        /// <summary>
+        ///     Gets or sets the <see cref="ResponseStatusCode"/>.
+        /// </summary>
         public ResponseStatusCode Code { get; set; }
 
-        [JsonProperty(PropertyName = "attributes")]
+        /// <summary>
+        ///     Gets or sets the attributes <see cref="Dictionary{TKey,TValue}"/> with protocol-level information.
+        /// </summary>
         public Dictionary<string, object> Attributes { get; set; }
 
-        [JsonProperty(PropertyName = "message")]
+        /// <summary>
+        ///     Gets or sets the message which is just a human-readable string usually associated with errors.
+        /// </summary>
         public string Message { get; set; }
     }
 
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/ResponseStatusCode.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/ResponseStatusCode.cs
index 78f8759..b1a841a 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/ResponseStatusCode.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/ResponseStatusCode.cs
@@ -77,10 +77,10 @@
         ServerError = 500,
 
         /// <summary>
-        ///     The script submitted for processing evaluated in the ScriptEngine with errors and could not be processed.
-        ///     Check the script submitted for syntax errors or other problems and then resubmit.
+        ///     The request submitted for processing evaluated by the server with errors and could not be processed.
+        ///     Check the script or remote traversal submitted for errors or other problems and then resubmit.
         /// </summary>
-        ScriptEvaluationError = 597,
+        ServerEvaluationError = 597,
 
         /// <summary>
         ///     The server exceeded one of the timeout settings for the request and could therefore only partially responded
@@ -111,7 +111,7 @@
                 case ResponseStatusCode.MalformedRequest:
                 case ResponseStatusCode.InvalidRequestArguments:
                 case ResponseStatusCode.ServerError:
-                case ResponseStatusCode.ScriptEvaluationError:
+                case ResponseStatusCode.ServerEvaluationError:
                 case ResponseStatusCode.ServerTimeout:
                 case ResponseStatusCode.ServerSerializationError:
                     return true;
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/DriverRemoteTraversal.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/DriverRemoteTraversal.cs
index 2197388..cf50646 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/DriverRemoteTraversal.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/DriverRemoteTraversal.cs
@@ -33,10 +33,6 @@
             IEnumerable<Traverser> traversers)
         {
             Traversers = traversers;
-
-            #pragma warning disable 612,618
-            SideEffects = new DriverRemoteTraversalSideEffects(gremlinClient, requestId);
-            #pragma warning disable 612,618
         }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/DriverRemoteTraversalSideEffects.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/DriverRemoteTraversalSideEffects.cs
deleted file mode 100644
index f7c6ca8..0000000
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/DriverRemoteTraversalSideEffects.cs
+++ /dev/null
@@ -1,129 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using Gremlin.Net.Driver.Messages;
-using Gremlin.Net.Process;
-using Gremlin.Net.Process.Traversal;
-
-namespace Gremlin.Net.Driver.Remote
-{
-    #pragma warning disable 612,618
-    internal class DriverRemoteTraversalSideEffects : ITraversalSideEffects
-    {
-        private readonly IGremlinClient _gremlinClient;
-        private readonly List<string> _keys = new List<string>();
-        private readonly Guid _serverSideEffectId;
-        private readonly Dictionary<string, object> _sideEffects = new Dictionary<string, object>();
-        private bool _closed;
-        private bool _retrievedAllKeys;
-
-        public DriverRemoteTraversalSideEffects(IGremlinClient gremlinClient, Guid serverSideEffectId)
-        {
-            _gremlinClient = gremlinClient;
-            _serverSideEffectId = serverSideEffectId;
-        }
-
-        public void Dispose()
-        {
-            Close();
-        }
-
-        public IReadOnlyCollection<string> Keys()
-        {
-            if (_closed && !_retrievedAllKeys)
-                throw new InvalidOperationException("Traversal has been closed - side-effect keys cannot be retrieved");
-            if (!_retrievedAllKeys)
-            {
-                _keys.AddRange(RetrieveKeys());
-                _retrievedAllKeys = true;
-            }
-            return _keys;
-        }
-
-        private IEnumerable<string> RetrieveKeys()
-        {
-            return _gremlinClient.SubmitAsync<string>(SideEffectKeysMessage()).Result;
-        }
-
-        private RequestMessage SideEffectKeysMessage()
-        {
-            return RequestMessage.Build(Tokens.OpsKeys)
-                .AddArgument(Tokens.ArgsSideEffect, _serverSideEffectId)
-                .Processor(Tokens.ProcessorTraversal)
-                .Create();
-        }
-
-        public object Get(string key)
-        {
-            if (!Keys().Contains(key))
-                throw new KeyNotFoundException($"Side effect key {key} does not exist");
-            if (!_sideEffects.ContainsKey(key))
-            {
-                if (_closed)
-                    throw new InvalidOperationException(
-                        "Traversal has been closed - no new side-effects can be retrieved");
-                _sideEffects.Add(key, RetrieveSideEffectsForKey(key));
-            }
-            return _sideEffects[key];
-        }
-
-        private object RetrieveSideEffectsForKey(string key)
-        {
-            return _gremlinClient.SubmitAsync<object>(SideEffectGatherMessage(key)).Result;
-        }
-
-        private RequestMessage SideEffectGatherMessage(string key)
-        {
-            return RequestMessage.Build(Tokens.OpsGather)
-                .AddArgument(Tokens.ArgsSideEffect, _serverSideEffectId)
-                .AddArgument(Tokens.ArgsSideEffectKey, key)
-                .AddArgument(Tokens.ArgsAliases, new Dictionary<string, string> {{"g", "g"}})
-                .Processor(Tokens.ProcessorTraversal)
-                .Create();
-        }
-
-        public void Close()
-        {
-            if (_closed) return;
-            CloseSideEffects();
-            _closed = true;
-        }
-
-        private void CloseSideEffects()
-        {
-            _gremlinClient.SubmitAsync<object>(SideEffectCloseMessage()).WaitUnwrap();
-        }
-
-        private RequestMessage SideEffectCloseMessage()
-        {
-            return RequestMessage.Build(Tokens.OpsClose)
-                .AddArgument(Tokens.ArgsSideEffect, _serverSideEffectId)
-                .Processor(Tokens.ProcessorTraversal)
-                .Create();
-        }
-    }
-    #pragma warning disable 612,618
-}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/ResponseHandlerForSingleRequestMessage.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/ResponseHandlerForSingleRequestMessage.cs
new file mode 100644
index 0000000..fafa7d9
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/ResponseHandlerForSingleRequestMessage.cs
@@ -0,0 +1,60 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Gremlin.Net.Driver.Messages;
+
+namespace Gremlin.Net.Driver
+{
+    internal class ResponseHandlerForSingleRequestMessage<T> : IResponseHandlerForSingleRequestMessage
+    {
+        public Task<ResultSet<T>> Result => _tcs.Task;
+
+        private readonly TaskCompletionSource<ResultSet<T>> _tcs =
+            new TaskCompletionSource<ResultSet<T>>(TaskCreationOptions.RunContinuationsAsynchronously);
+        
+        private readonly List<T> _result = new List<T>();
+
+        public void HandleReceived(ResponseMessage<List<object>> received)
+        {
+            foreach (var d in received.Result.Data)
+            {
+                _result.Add((T) d);
+            }
+        }
+
+        public void Finalize(Dictionary<string, object> statusAttributes)
+        {
+            var resultSet =
+                new ResultSet<T>(_result, statusAttributes);
+            _tcs.TrySetResult(resultSet);
+        }
+
+        public void HandleFailure(Exception objException)
+        {
+            _tcs.TrySetException(objException);
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/ResultsAggregation/AggregatorFactory.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/ResultsAggregation/AggregatorFactory.cs
deleted file mode 100644
index 522225d..0000000
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/ResultsAggregation/AggregatorFactory.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-using System.Collections.Generic;
-
-namespace Gremlin.Net.Driver.ResultsAggregation
-{
-    #pragma warning disable 612,618
-    internal class AggregatorFactory
-    {
-        private readonly Dictionary<string, IAggregator> _aggregatorByAggregateToType =
-            new Dictionary<string, IAggregator>
-            {
-                {Tokens.ValAggregateToMap, new DictionaryAggregator()},
-                {Tokens.ValAggregateToBulkSet, new TraverserAggregator()}
-            };
-
-        public IAggregator GetAggregatorFor(string aggregateTo)
-        {
-            if (_aggregatorByAggregateToType.ContainsKey(aggregateTo))
-                return _aggregatorByAggregateToType[aggregateTo];
-            return new DefaultAggregator();
-        }
-    }
-    #pragma warning disable 612,618
-}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/ResultsAggregation/DefaultAggregator.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/ResultsAggregation/DefaultAggregator.cs
deleted file mode 100644
index 82b247b..0000000
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/ResultsAggregation/DefaultAggregator.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-using System.Collections.Generic;
-
-namespace Gremlin.Net.Driver.ResultsAggregation
-{
-    internal class DefaultAggregator : IAggregator
-    {
-        private readonly List<dynamic> _result = new List<dynamic>();
-
-        public void Add(object value)
-        {
-            _result.Add(value);
-        }
-
-        public object GetAggregatedResult()
-        {
-            return _result;
-        }
-    }
-}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/ResultsAggregation/DictionaryAggregator.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/ResultsAggregation/DictionaryAggregator.cs
deleted file mode 100644
index 75764e3..0000000
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/ResultsAggregation/DictionaryAggregator.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-using System.Collections.Generic;
-using System.Linq;
-
-namespace Gremlin.Net.Driver.ResultsAggregation
-{
-    internal class DictionaryAggregator : IAggregator
-    {
-        private readonly Dictionary<string, dynamic> _result = new Dictionary<string, dynamic>();
-
-        public void Add(object value)
-        {
-            var newEntry = ((Dictionary<string, dynamic>) value).First();
-            _result.Add(newEntry.Key, newEntry.Value);
-        }
-
-        public object GetAggregatedResult()
-        {
-            return _result;
-        }
-    }
-}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/ResultsAggregation/IAggregator.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/ResultsAggregation/IAggregator.cs
deleted file mode 100644
index bcc036a..0000000
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/ResultsAggregation/IAggregator.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-namespace Gremlin.Net.Driver.ResultsAggregation
-{
-    internal interface IAggregator
-    {
-        void Add(object value);
-        object GetAggregatedResult();
-    }
-}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/ResultsAggregation/TraverserAggregator.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/ResultsAggregation/TraverserAggregator.cs
deleted file mode 100644
index 2d18804..0000000
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/ResultsAggregation/TraverserAggregator.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-using System.Collections.Generic;
-using Gremlin.Net.Process.Traversal;
-
-namespace Gremlin.Net.Driver.ResultsAggregation
-{
-    internal class TraverserAggregator : IAggregator
-    {
-        private readonly Dictionary<object, long> _result = new Dictionary<object, long>();
-
-        public void Add(object value)
-        {
-            var traverser = (Traverser) value;
-            _result.Add(traverser.Object, traverser.Bulk);
-        }
-
-        public object GetAggregatedResult()
-        {
-            return _result;
-        }
-    }
-}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/SingleMessageResultReceiver.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/SingleMessageResultReceiver.cs
deleted file mode 100644
index 7b66e61..0000000
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/SingleMessageResultReceiver.cs
+++ /dev/null
@@ -1,90 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.Threading.Tasks;
-using Gremlin.Net.Driver.Messages;
-using Gremlin.Net.Driver.ResultsAggregation;
-using Gremlin.Net.Structure.IO.GraphSON;
-using Newtonsoft.Json.Linq;
-
-namespace Gremlin.Net.Driver
-{
-    internal class ResponseHandlerForSingleRequestMessage<T> : IResponseHandlerForSingleRequestMessage
-    {
-        public Task<ResultSet<T>> Result => _tcs.Task;
-
-        private readonly TaskCompletionSource<ResultSet<T>> _tcs =
-            new TaskCompletionSource<ResultSet<T>>(TaskCreationOptions.RunContinuationsAsynchronously);
-
-        private readonly GraphSONReader _graphSONReader;
-        private bool _isAggregatingSideEffects;
-        private IAggregator _aggregator;
-        private readonly List<T> _result = new List<T>();
-
-        public ResponseHandlerForSingleRequestMessage(GraphSONReader graphSonReader)
-        {
-            _graphSONReader = graphSonReader;
-        }
-
-        public void HandleReceived(ResponseMessage<JToken> received)
-        {
-            var receivedData = typeof(T) == typeof(JToken)
-                ? new[] {received.Result.Data}
-                : _graphSONReader.ToObject(received.Result.Data);
-            #pragma warning disable 612,618
-            foreach (var d in receivedData)
-            {
-                if (received.Result.Meta.ContainsKey(Tokens.ArgsSideEffectKey))
-                {
-                    if (_aggregator == null)
-                        _aggregator =
-                            new AggregatorFactory().GetAggregatorFor(
-                                (string) received.Result.Meta[Tokens.ArgsAggregateTo]);
-                    _aggregator.Add(d);
-                    _isAggregatingSideEffects = true;
-                }
-                else
-                {
-                    _result.Add(d);
-                }
-            }
-            #pragma warning disable 612,618
-        }
-
-        public void Finalize(Dictionary<string, object> statusAttributes)
-        {
-            var resultSet =
-                new ResultSet<T>(
-                    _isAggregatingSideEffects ? new List<T> {(T) _aggregator.GetAggregatedResult()} : _result,
-                    statusAttributes);
-            _tcs.TrySetResult(resultSet);
-        }
-
-        public void HandleFailure(Exception objException)
-        {
-            _tcs.TrySetException(objException);
-        }
-    }
-}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/Tokens.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/Tokens.cs
index 1833855..f35b128 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/Tokens.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/Tokens.cs
@@ -32,10 +32,10 @@
     public class Tokens
     {
         /// <summary>
-        ///     The key for the unique identifier of the request. 
+        ///     The key for the unique identifier of the request.
         /// </summary>
         public static string RequestId = "requestId";
-        
+
         /// <summary>
         ///     Operation used by the client to authenticate itself.
         /// </summary>
@@ -52,18 +52,6 @@
         public static string OpsEval = "eval";
 
         /// <summary>
-        ///     Operation used to get a particular side-effect as produced by a previously executed Traversal.
-        /// </summary>
-        [Obsolete("As of release 3.3.8, not replaced, prefer use of cap()-step to retrieve side-effects as part of traversal iteration", false)]
-        public static string OpsGather = "gather";
-
-        /// <summary>
-        ///     Operation used to get all the keys of all side-effects as produced by a previously executed Traversal.
-        /// </summary>
-        [Obsolete("As of release 3.3.8, not replaced, prefer use of cap()-step to retrieve side-effects as part of traversal iteration", false)]
-        public static string OpsKeys = "keys";
-
-        /// <summary>
         ///     Operation used to get all the keys of all side-effects as produced by a previously executed Traversal.
         /// </summary>
         public static string OpsClose = "close";
@@ -113,24 +101,6 @@
         public static string ArgsUserAgent = "userAgent";
 
         /// <summary>
-        ///     Argument name that allows to specify the unique identifier for the request.
-        /// </summary>
-        [Obsolete("As of release 3.3.8, not replaced, prefer use of cap()-step to retrieve side-effects as part of traversal iteration", false)]
-        public static string ArgsSideEffect = "sideEffect";
-
-        /// <summary>
-        ///     Argument name that allows to specify the key for a specific side-effect.
-        /// </summary>
-        [Obsolete("As of release 3.3.8, not replaced, prefer use of cap()-step to retrieve side-effects as part of traversal iteration", false)]
-        public static string ArgsSideEffectKey = "sideEffectKey";
-
-        /// <summary>
-        ///     <see cref="ResponseMessage{T}" /> argument that describes how side-effect data should be treated.
-        /// </summary>
-        [Obsolete("As of release 3.3.8, not replaced, prefer use of cap()-step to retrieve side-effects as part of traversal iteration", false)]
-        public static string ArgsAggregateTo = "aggregateTo";
-
-        /// <summary>
         ///     Argument name that allows definition of the flavor of Gremlin used (e.g. gremlin-groovy) to process the request.
         /// </summary>
         public static string ArgsLanguage = "language";
@@ -146,11 +116,5 @@
         ///     authentication mechanism required by the server.
         /// </summary>
         public static string ArgsSasl = "sasl";
-
-        [Obsolete("As of release 3.3.8, not replaced, prefer use of cap()-step to retrieve side-effects as part of traversal iteration", false)]
-        internal static string ValAggregateToMap = "map";
-
-        [Obsolete("As of release 3.3.8, not replaced, prefer use of cap()-step to retrieve side-effects as part of traversal iteration", false)]
-        internal static string ValAggregateToBulkSet = "bulkset";
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj b/gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj
index 38f74aa..5e82079 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj
+++ b/gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj
@@ -15,19 +15,17 @@
 limitations under the License.
 -->
 
-<!--  THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml -->
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup Label="Build">
-    <TargetFrameworks>netstandard1.3;netstandard2.0</TargetFrameworks>
+    <TargetFramework>netstandard2.0</TargetFramework>
     <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
   </PropertyGroup>
 
   <PropertyGroup Label="Package">
-    <Version>3.4.12-SNAPSHOT</Version>
-    <FileVersion>3.4.12.0</FileVersion>
-    <AssemblyVersion>3.4.0.0</AssemblyVersion>
+    <!-- do not edit the version directly - maven updates it automatically -->
+    <Version>3.5.1-SNAPSHOT</Version>
     <Title>Gremlin.Net</Title>
     <Authors>Apache TinkerPop</Authors>
     <Description>Gremlin.Net for Apache TinkerPop™ is a language variant and driver for .NET.
@@ -71,18 +69,12 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
-    <PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
+    <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
+    <PackageReference Include="System.Text.Json" Version="4.7.1" />
     <PackageReference Include="Microsoft.CSharp" Version="4.3.0" />
     <PackageReference Include="Polly" Version="7.2.0" />
   </ItemGroup>
 
-  <ItemGroup Condition="'$(TargetFramework)' == 'netstandard1.3'">
-    <PackageReference Include="System.Net.WebSockets" Version="4.3.0" />
-    <PackageReference Include="System.Net.WebSockets.Client" Version="4.3.2" />
-    <PackageReference Include="System.Reflection.TypeExtensions" Version="4.3.0" />
-  </ItemGroup>
-
   <ItemGroup>
     <None Include="../../LICENSE" Pack="true" PackagePath="" />
     <None Include="../../NOTICE" Pack="true" PackagePath="" />
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Remote/RemoteStrategy.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Remote/RemoteStrategy.cs
index 098a46d..d361ac4 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Remote/RemoteStrategy.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Remote/RemoteStrategy.cs
@@ -54,7 +54,6 @@
         {
             if (traversal.Traversers != null) return;
             var remoteTraversal = await _remoteConnection.SubmitAsync<S, E>(traversal.Bytecode).ConfigureAwait(false);
-            traversal.SideEffects = remoteTraversal.SideEffects;
             traversal.Traversers = remoteTraversal.Traversers;
         }
     }
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Barrier.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Barrier.cs
index 0f86f32..c65994b 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Barrier.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Barrier.cs
@@ -21,7 +21,6 @@
 
 #endregion
 
-// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml
 using System;
 using System.Collections.Generic;
 
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Bytecode.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Bytecode.cs
index e09c533..7149e8b 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Bytecode.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Bytecode.cs
@@ -110,12 +110,23 @@
 
         private object ConvertArgument(object argument, bool searchBindings)
         {
+            if (null == argument)
+            {
+                return null;
+            }
+
             if (searchBindings)
             {
                 var variable = Bindings.GetBoundVariable(argument);
                 if (variable != null)
                     return new Binding(variable, ConvertArgument(argument, false));
             }
+
+            if (argument is ITraversal traversal && !traversal.IsAnonymous)
+                throw new ArgumentException(
+                    $"The child traversal of {traversal.Bytecode} was not spawned anonymously - use the __ class rather than a TraversalSource to construct the child traversal");
+
+            
             if (IsDictionaryType(argument.GetType()))
             {
                 var dict = new Dictionary<object, object>();
@@ -158,4 +169,4 @@
             return type.IsConstructedGenericType && type.GetGenericTypeDefinition() == typeof(HashSet<>);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Cardinality.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Cardinality.cs
index caced7d..65663d6 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Cardinality.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Cardinality.cs
@@ -21,7 +21,6 @@
 
 #endregion
 
-// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml
 using System;
 using System.Collections.Generic;
 
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Column.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Column.cs
index cacf886..66a6edd 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Column.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Column.cs
@@ -21,7 +21,6 @@
 
 #endregion
 
-// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml
 using System;
 using System.Collections.Generic;
 
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/ConnectedComponent.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/ConnectedComponent.cs
index ca1f53e..860e87a 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/ConnectedComponent.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/ConnectedComponent.cs
@@ -21,7 +21,6 @@
 
 #endregion
 
-// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml
 using System;
 using System.Collections;
 using System.Collections.Generic;
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/DefaultTraversal.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/DefaultTraversal.cs
index 2b6d378..38e031c 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/DefaultTraversal.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/DefaultTraversal.cs
@@ -40,12 +40,11 @@
         ///     Gets the <see cref="Traversal.Bytecode" /> representation of this traversal.
         /// </summary>
         public Bytecode Bytecode { get; protected set; }
-
+        
         /// <summary>
-        ///     Gets or sets the <see cref="ITraversalSideEffects" /> of this traversal.
+        ///     Determines if this traversal was spawned anonymously or not.
         /// </summary>
-        [Obsolete("As of release 3.3.8, not replaced, prefer use of cap()-step to retrieve side-effects as part of traversal iteration", false)]
-        public ITraversalSideEffects SideEffects { get; set; }
+        public bool IsAnonymous { get; protected set; }
 
         /// <summary>
         ///     Gets or sets the <see cref="Traverser" />'s of this traversal that hold the results of the traversal.
@@ -71,7 +70,6 @@
         /// <inheritdoc />
         public void Dispose()
         {
-            Dispose(true);
         }
 
         /// <inheritdoc />
@@ -261,15 +259,6 @@
             return objs;
         }
 
-        /// <inheritdoc />
-        protected virtual void Dispose(bool disposing)
-        {
-            if (disposing)
-                #pragma warning disable 612,618
-                SideEffects?.Dispose();
-                #pragma warning disable 612,618
-        }
-
         /// <summary>
         ///     Starts a promise to execute a function on the current traversal that will be completed in the future.
         /// </summary>
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Direction.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Direction.cs
index 92d9416..8c3ed4a 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Direction.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Direction.cs
@@ -21,7 +21,6 @@
 
 #endregion
 
-// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml
 using System;
 using System.Collections.Generic;
 
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphSONVersion.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphSONVersion.cs
index 366c48c..e79c86e 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphSONVersion.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphSONVersion.cs
@@ -21,7 +21,6 @@
 
 #endregion
 
-// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml
 using System;
 using System.Collections.Generic;
 
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
index b6d3a83..8f6df56 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
@@ -25,7 +25,6 @@
 using System.Linq;
 using Gremlin.Net.Structure;
 
-// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml
 namespace Gremlin.Net.Process.Traversal
 {
     /// <summary>
@@ -37,7 +36,7 @@
         ///     Initializes a new instance of the <see cref="GraphTraversal{SType, EType}" /> class.
         /// </summary>
         public GraphTraversal()
-            : this(new List<ITraversalStrategy>(), new Bytecode())
+            : this(new List<ITraversalStrategy>(), new Bytecode(), true)
         {
         }
 
@@ -47,9 +46,21 @@
         /// <param name="traversalStrategies">The traversal strategies to be used by this graph traversal at evaluation time.</param>
         /// <param name="bytecode">The <see cref="Bytecode" /> associated with the construction of this graph traversal.</param>
         public GraphTraversal(ICollection<ITraversalStrategy> traversalStrategies, Bytecode bytecode)
+            : this(traversalStrategies, bytecode, false)
+        {
+        }
+
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="GraphTraversal{SType, EType}" /> class.
+        /// </summary>
+        /// <param name="traversalStrategies">The traversal strategies to be used by this graph traversal at evaluation time.</param>
+        /// <param name="bytecode">The <see cref="Bytecode" /> associated with the construction of this graph traversal.</param>
+        /// <param name="anonymous">Set to true if spawned from an anonymous traversal source and false otherwise.</param>
+        private GraphTraversal(ICollection<ITraversalStrategy> traversalStrategies, Bytecode bytecode, bool anonymous)
         {
             TraversalStrategies = traversalStrategies;
             Bytecode = bytecode;
+            IsAnonymous = anonymous;
         }
 
         private static GraphTraversal<S2, E2> Wrap<S2, E2>(GraphTraversal<S, E> traversal)
@@ -59,7 +70,7 @@
                 return traversal as GraphTraversal<S2, E2>;
             }
             // New wrapper
-            return new GraphTraversal<S2, E2>(traversal.TraversalStrategies, traversal.Bytecode);
+            return new GraphTraversal<S2, E2>(traversal.TraversalStrategies, traversal.Bytecode, traversal.IsAnonymous);
         }
 
 
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversalSource.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversalSource.cs
index 7a7f643..db4c521 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversalSource.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversalSource.cs
@@ -28,7 +28,6 @@
 using Gremlin.Net.Process.Traversal.Strategy.Decoration;
 using Gremlin.Net.Structure;
 
-// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml
 namespace Gremlin.Net.Process.Traversal
 {
 #pragma warning disable 1591
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GryoVersion.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GryoVersion.cs
index 01d2a99..e34c7b3 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GryoVersion.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GryoVersion.cs
@@ -21,7 +21,6 @@
 
 #endregion
 
-// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml
 using System;
 using System.Collections.Generic;
 
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/IO.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/IO.cs
index 3a57d4b..b9e0fdd 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/IO.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/IO.cs
@@ -21,7 +21,6 @@
 
 #endregion
 
-// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml
 using System;
 using System.Collections;
 using System.Collections.Generic;
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/ITraversal.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/ITraversal.cs
index 22f792a..95cbb74 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/ITraversal.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/ITraversal.cs
@@ -38,13 +38,11 @@
         ///     Gets the <see cref="Bytecode" /> representation of this traversal.
         /// </summary>
         Bytecode Bytecode { get; }
-
+        
         /// <summary>
-        ///     Gets or sets the <see cref="ITraversalSideEffects" /> of this traversal.
+        ///     Determines if this traversal was spawned anonymously or not.
         /// </summary>
-        #pragma warning disable 612,618
-        ITraversalSideEffects SideEffects { get; set; }
-        #pragma warning disable 612,618
+        bool IsAnonymous { get;  }
 
         /// <summary>
         ///     Gets or sets the <see cref="Traverser" />'s of this traversal that hold the results of the traversal.
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/ITraversalSideEffects.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/ITraversalSideEffects.cs
deleted file mode 100644
index d8d9fc1..0000000
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/ITraversalSideEffects.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-using System;
-using System.Collections.Generic;
-
-namespace Gremlin.Net.Process.Traversal
-{
-    /// <summary>
-    ///     A <see cref="ITraversal" /> can maintain global sideEffects.
-    /// </summary>
-    [Obsolete("As of release 3.3.8, not replaced, prefer use of cap()-step to retrieve side-effects as part of traversal iteration", false)]
-    public interface ITraversalSideEffects : IDisposable
-    {
-        /// <summary>
-        ///     Retrieves the keys of the side-effect that can be supplied to <see cref="Get" />.
-        /// </summary>
-        /// <returns>The keys of the side-effect.</returns>
-        IReadOnlyCollection<string> Keys();
-
-        /// <summary>
-        ///     Gets the side-effect associated with the provided key.
-        /// </summary>
-        /// <param name="key">The key to get the value for.</param>
-        /// <returns>The value associated with key.</returns>
-        object Get(string key);
-
-        /// <summary>
-        ///     Invalidates the side effect cache for traversal.
-        /// </summary>
-        void Close();
-    }
-}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Instruction.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Instruction.cs
index 65847c5..1063b33 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Instruction.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Instruction.cs
@@ -21,12 +21,15 @@
 
 #endregion
 
+using System;
+using System.Linq;
+
 namespace Gremlin.Net.Process.Traversal
 {
     /// <summary>
     ///     Represents a <see cref="Bytecode" /> instruction by an operator name and its arguments.
     /// </summary>
-    public class Instruction
+    public class Instruction : IEquatable<Instruction>
     {   
         /// <summary>
         ///     Initializes a new instance of the <see cref="Instruction" /> class.
@@ -48,5 +51,50 @@
         ///     Gets the arguments.
         /// </summary>
         public dynamic[] Arguments { get; }
+
+        /// <summary>
+        ///     String representation of the <see cref="Instruction"/>.
+        /// </summary>
+        public override string ToString()
+        {
+            return OperatorName + " [" + String.Join(",", Arguments) + "]";
+        }
+
+        /// <inheritdoc />
+        public bool Equals(Instruction other)
+        {
+            if (ReferenceEquals(null, other)) return false;
+            if (ReferenceEquals(this, other)) return true;
+            return OperatorName == other.OperatorName && Arguments.SequenceEqual(other.Arguments);
+        }
+
+        /// <inheritdoc />
+        public override bool Equals(object obj)
+        {
+            if (ReferenceEquals(null, obj)) return false;
+            if (ReferenceEquals(this, obj)) return true;
+            if (obj.GetType() != GetType()) return false;
+            return Equals((Instruction) obj);
+        }
+
+        /// <inheritdoc />
+        public override int GetHashCode()
+        {
+            unchecked
+            {
+                var hash = 19;
+                if (OperatorName != null)
+                {
+                    hash = hash * 397 + OperatorName.GetHashCode();
+                }
+
+                if (Arguments != null)
+                {
+                    hash = Arguments.Aggregate(hash, (current, value) => current * 31 + value.GetHashCode());
+                }
+
+                return hash;
+            }
+        }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/NamingConversions.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/NamingConversions.cs
index eadaa0e..a650dc5 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/NamingConversions.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/NamingConversions.cs
@@ -23,7 +23,6 @@
 
 using System.Collections.Generic;
 
-// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml
 namespace Gremlin.Net.Process.Traversal
 {
     internal static class NamingConversions
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Operator.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Operator.cs
index 8b87e40..ce33569 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Operator.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Operator.cs
@@ -21,7 +21,6 @@
 
 #endregion
 
-// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml
 using System;
 using System.Collections.Generic;
 
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Order.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Order.cs
index 9fce332..fca67ab 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Order.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Order.cs
@@ -21,7 +21,6 @@
 
 #endregion
 
-// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml
 using System;
 using System.Collections.Generic;
 
@@ -38,20 +37,14 @@
 
         public static Order Asc => new Order("asc");
 
-        public static Order Decr => new Order("decr");
-
         public static Order Desc => new Order("desc");
 
-        public static Order Incr => new Order("incr");
-
         public static Order Shuffle => new Order("shuffle");
 
         private static readonly IDictionary<string, Order> Properties = new Dictionary<string, Order>
         {
             { "asc", Asc },
-            { "decr", Decr },
             { "desc", Desc },
-            { "incr", Incr },
             { "shuffle", Shuffle },
         };
 
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/P.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/P.cs
index b83e3c2..d37a614 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/P.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/P.cs
@@ -21,7 +21,6 @@
 
 #endregion
 
-// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml
 using System.Collections;
 using System.Collections.Generic;
 using System.Linq;
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/PageRank.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/PageRank.cs
index 73d248a..5c2ade9 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/PageRank.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/PageRank.cs
@@ -21,7 +21,6 @@
 
 #endregion
 
-// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml
 using System;
 using System.Collections;
 using System.Collections.Generic;
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/PeerPressure.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/PeerPressure.cs
index 185879e..fde3b41 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/PeerPressure.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/PeerPressure.cs
@@ -21,7 +21,6 @@
 
 #endregion
 
-// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml
 using System;
 using System.Collections;
 using System.Collections.Generic;
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Pick.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Pick.cs
index b7dd8c2..f0312a3 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Pick.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Pick.cs
@@ -21,7 +21,6 @@
 
 #endregion
 
-// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml
 using System;
 using System.Collections.Generic;
 
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Pop.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Pop.cs
index 1210f5c..196ce01 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Pop.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Pop.cs
@@ -21,7 +21,6 @@
 
 #endregion
 
-// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml
 using System;
 using System.Collections.Generic;
 
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Scope.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Scope.cs
index 2df6a95..ff70069 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Scope.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Scope.cs
@@ -21,7 +21,6 @@
 
 #endregion
 
-// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml
 using System;
 using System.Collections.Generic;
 
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/ShortestPath.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/ShortestPath.cs
index f125e42..238a5e7 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/ShortestPath.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/ShortestPath.cs
@@ -21,7 +21,6 @@
 
 #endregion
 
-// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml
 using System;
 using System.Collections;
 using System.Collections.Generic;
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/AbstractTraversalStrategy.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/AbstractTraversalStrategy.cs
index e5d3dfe..418ac7e 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/AbstractTraversalStrategy.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/AbstractTraversalStrategy.cs
@@ -33,12 +33,54 @@
     /// </summary>
     public abstract class AbstractTraversalStrategy : ITraversalStrategy, IEquatable<AbstractTraversalStrategy>
     {
+        private const string BaseNamespace = "org.apache.tinkerpop.gremlin.process.traversal.strategy.";
+
+        /// <summary>
+        /// Java namespace for decoration strategies.
+        /// </summary>
+        protected const string DecorationNamespace = BaseNamespace + "decoration.";
+
+        /// <summary>
+        /// Java namespace for finalization strategies.
+        /// </summary>
+        protected const string FinalizationNamespace = BaseNamespace + "finalization.";
+
+        /// <summary>
+        /// Java namespace for optimization strategies.
+        /// </summary>
+        protected const string OptimizationNamespace = BaseNamespace + "optimization.";
+
+        /// <summary>
+        /// Java namespace for verification strategies.
+        /// </summary>
+        protected const string VerificationNamespace = BaseNamespace + "verification.";
+
+        /// <summary>
+        /// Java namespace for computer decoration strategies.
+        /// </summary>
+        protected const string ComputerDecorationNamespace =
+            "org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.";
+        
+        /// <summary>
+        ///     Creates a new <see cref="AbstractTraversalStrategy"/> instance.
+        /// </summary>
+        /// <param name="fqcn">The fully qualified class name (FQCN) from the equivalent Java strategy.</param>
+        protected AbstractTraversalStrategy(string fqcn)
+        {
+            Fqcn = fqcn;
+        }
+
         /// <summary>
         ///     Gets the name of the strategy.
         /// </summary>
         public string StrategyName => GetType().Name;
 
         /// <summary>
+        ///     Gets the fully qualified class name (FQCN) from the equivalent Java strategy.
+        /// </summary>
+        public string Fqcn { get; }
+        
+        /// <summary>
         ///     Gets the configuration of the strategy.
         /// </summary>
         public Dictionary<string, dynamic> Configuration { get; } = new Dictionary<string, dynamic>();
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Decoration/ConnectiveStrategy.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Decoration/ConnectiveStrategy.cs
index 2bca7c2..f21a07b 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Decoration/ConnectiveStrategy.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Decoration/ConnectiveStrategy.cs
@@ -29,5 +29,13 @@
     /// </summary>
     public class ConnectiveStrategy : AbstractTraversalStrategy
     {
+        private const string JavaFqcn = DecorationNamespace + nameof(ConnectiveStrategy);
+
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="ConnectiveStrategy" /> class.
+        /// </summary>
+        public ConnectiveStrategy() : base(JavaFqcn)
+        {
+        }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Decoration/ElementIdStrategy.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Decoration/ElementIdStrategy.cs
index 6079f58..90898e9 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Decoration/ElementIdStrategy.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Decoration/ElementIdStrategy.cs
@@ -28,5 +28,13 @@
     /// </summary>
     public class ElementIdStrategy : AbstractTraversalStrategy
     {
+        private const string JavaFqcn = DecorationNamespace + nameof(ElementIdStrategy);
+        
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="ElementIdStrategy" /> class.
+        /// </summary>
+        public ElementIdStrategy() : base(JavaFqcn)
+        {
+        }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Decoration/HaltedTraverserStrategy.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Decoration/HaltedTraverserStrategy.cs
index f93dcb2..6ae8876 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Decoration/HaltedTraverserStrategy.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Decoration/HaltedTraverserStrategy.cs
@@ -26,11 +26,14 @@
 #pragma warning disable 1591
     public class HaltedTraverserStrategy : AbstractTraversalStrategy
     {
-        public HaltedTraverserStrategy()
+        private const string JavaFqcn = DecorationNamespace + nameof(HaltedTraverserStrategy);
+        
+        public HaltedTraverserStrategy() : base(JavaFqcn)
         {
         }
 
         public HaltedTraverserStrategy(string haltedTraverserFactoryName = null)
+            : this()
         {
             if (haltedTraverserFactoryName != null)
                 Configuration["haltedTraverserFactory"] = haltedTraverserFactoryName;
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Decoration/OptionsStrategy.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Decoration/OptionsStrategy.cs
index a5d70b0..aee9118 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Decoration/OptionsStrategy.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Decoration/OptionsStrategy.cs
@@ -31,10 +31,12 @@
     /// </summary>
     public class OptionsStrategy : AbstractTraversalStrategy
     {
+        private const string JavaFqcn = DecorationNamespace + nameof(OptionsStrategy);
+        
         /// <summary>
         ///     Initializes a new instance of the <see cref="OptionsStrategy" /> class.
         /// </summary>
-        public OptionsStrategy()
+        public OptionsStrategy() : base(JavaFqcn)
         {
         }
 
@@ -43,6 +45,7 @@
         /// </summary>
         /// <param name="options">Specifies the options for the traversal.</param>
         public OptionsStrategy(IDictionary<string,object> options)
+            : this()
         {
             foreach(var item in options)
             {
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Decoration/PartitionStrategy.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Decoration/PartitionStrategy.cs
index 729c63c..8c59ad4 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Decoration/PartitionStrategy.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Decoration/PartitionStrategy.cs
@@ -30,10 +30,12 @@
     /// </summary>
     public class PartitionStrategy : AbstractTraversalStrategy
     {
+        private const string JavaFqcn = DecorationNamespace + nameof(PartitionStrategy);
+        
         /// <summary>
         ///     Initializes a new instance of the <see cref="PartitionStrategy" /> class.
         /// </summary>
-        public PartitionStrategy()
+        public PartitionStrategy() : base(JavaFqcn)
         {
         }
 
@@ -49,6 +51,7 @@
         /// <param name="includeMetaProperties">Set to true if vertex properties should get assigned to partitions.</param>
         public PartitionStrategy(string partitionKey = null, string writePartition = null,
             IEnumerable<string> readPartitions = null, bool? includeMetaProperties = null)
+            : this()
         {
             if (partitionKey != null)
                 Configuration["partitionKey"] = partitionKey;
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Decoration/SeedStrategy.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Decoration/SeedStrategy.cs
new file mode 100644
index 0000000..d4ffbde
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Decoration/SeedStrategy.cs
@@ -0,0 +1,53 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System.Collections.Generic;
+
+namespace Gremlin.Net.Process.Traversal.Strategy.Decoration
+{
+    /// <summary>
+    ///     A strategy that resets the specified {@code seed} value for Seedable steps like coin(), sample()
+    ///     and Order.shuffle, which in turn will produce deterministic results from those steps.
+    /// </summary>
+    public class SeedStrategy : AbstractTraversalStrategy
+    {
+        private const string JavaFqcn = DecorationNamespace + nameof(SeedStrategy);
+        
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="SeedStrategy" /> class.
+        /// </summary>
+        public SeedStrategy() : base(JavaFqcn)
+        {
+        }
+
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="SeedStrategy" /> class.
+        /// </summary>
+        /// <param name="seed">Specifies the seed the traversal will use.</param>
+        public SeedStrategy(long seed)
+            : this()
+        {
+            Configuration["seed"] = seed;
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Decoration/SubgraphStrategy.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Decoration/SubgraphStrategy.cs
index ae6a46e..6e7f333 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Decoration/SubgraphStrategy.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Decoration/SubgraphStrategy.cs
@@ -28,10 +28,12 @@
     /// </summary>
     public class SubgraphStrategy : AbstractTraversalStrategy
     {
+        private const string JavaFqcn = DecorationNamespace + nameof(SubgraphStrategy);
+        
         /// <summary>
         ///     Initializes a new instance of the <see cref="SubgraphStrategy" /> class.
         /// </summary>
-        public SubgraphStrategy()
+        public SubgraphStrategy() : base(JavaFqcn)
         {
         }
 
@@ -43,6 +45,7 @@
         /// <param name="vertexProperties">Constrains vertex properties for the <see cref="ITraversal" />.</param>
         public SubgraphStrategy(ITraversal vertices = null, ITraversal edges = null,
             ITraversal vertexProperties = null)
+            : this()
         {
             if (vertices != null)
                 Configuration["vertices"] = vertices;
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Decoration/VertexProgramStrategy.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Decoration/VertexProgramStrategy.cs
index edacf60..17bfbaa 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Decoration/VertexProgramStrategy.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Decoration/VertexProgramStrategy.cs
@@ -29,13 +29,16 @@
 #pragma warning disable 1591
     public class VertexProgramStrategy : AbstractTraversalStrategy
     {
-        public VertexProgramStrategy()
+        private const string JavaFqcn = ComputerDecorationNamespace + nameof(VertexProgramStrategy);
+        
+        public VertexProgramStrategy() : base(JavaFqcn)
         {
         }
 
         public VertexProgramStrategy(string graphComputer = null, int? workers = null, string persist = null,
             string result = null, ITraversal vertices = null, ITraversal edges = null,
             Dictionary<string, dynamic> configuration = null)
+            : this()
         {
             if (graphComputer != null)
                 Configuration["graphComputer"] = graphComputer;
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Finalization/MatchAlgorithmStrategy.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Finalization/MatchAlgorithmStrategy.cs
index 96de864..3434e27 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Finalization/MatchAlgorithmStrategy.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Finalization/MatchAlgorithmStrategy.cs
@@ -26,11 +26,14 @@
 #pragma warning disable 1591
     public class MatchAlgorithmStrategy : AbstractTraversalStrategy
     {
-        public MatchAlgorithmStrategy()
+        private const string JavaFqcn = FinalizationNamespace + nameof(MatchAlgorithmStrategy);
+        
+        public MatchAlgorithmStrategy() : base(JavaFqcn)
         {
         }
 
-        public MatchAlgorithmStrategy(string matchAlgorithm = null)
+        public MatchAlgorithmStrategy(string matchAlgorithm)
+            : this()
         {
             if (matchAlgorithm != null)
                 Configuration["matchAlgorithm"] = matchAlgorithm;
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/AdjacentToIncidentStrategy.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/AdjacentToIncidentStrategy.cs
index bae85d7..cabc3b0 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/AdjacentToIncidentStrategy.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/AdjacentToIncidentStrategy.cs
@@ -28,5 +28,13 @@
     /// </summary>
     public class AdjacentToIncidentStrategy : AbstractTraversalStrategy
     {
+        private const string JavaFqcn = OptimizationNamespace + nameof(AdjacentToIncidentStrategy);
+        
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AdjacentToIncidentStrategy" /> class.
+        /// </summary>
+        public AdjacentToIncidentStrategy() : base(JavaFqcn)
+        {
+        }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/EarlyLimitStrategy.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/EarlyLimitStrategy.cs
index 0831c92..4513270 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/EarlyLimitStrategy.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/EarlyLimitStrategy.cs
@@ -28,5 +28,13 @@
     /// </summary>
     public class EarlyLimitStrategy : AbstractTraversalStrategy
     {
+        private const string JavaFqcn = OptimizationNamespace + nameof(EarlyLimitStrategy);
+        
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="EarlyLimitStrategy" /> class.
+        /// </summary>
+        public EarlyLimitStrategy() : base(JavaFqcn)
+        {
+        }
     }
 }
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/FilterRankingStrategy.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/FilterRankingStrategy.cs
index 3443e71..336e4b9 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/FilterRankingStrategy.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/FilterRankingStrategy.cs
@@ -28,5 +28,13 @@
     /// </summary>
     public class FilterRankingStrategy : AbstractTraversalStrategy
     {
+        private const string JavaFqcn = OptimizationNamespace + nameof(FilterRankingStrategy);
+        
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="FilterRankingStrategy" /> class.
+        /// </summary>
+        public FilterRankingStrategy() : base(JavaFqcn)
+        {
+        }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/GraphFilterStrategy.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/GraphFilterStrategy.cs
index 7d29b0d..7b62104 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/GraphFilterStrategy.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/GraphFilterStrategy.cs
@@ -26,6 +26,11 @@
 #pragma warning disable 1591
     public class GraphFilterStrategy : AbstractTraversalStrategy
     {
+        private const string JavaFqcn = OptimizationNamespace + nameof(GraphFilterStrategy);
+        
+        public GraphFilterStrategy() : base(JavaFqcn)
+        {
+        }
     }
 #pragma warning restore 1591
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/IdentityRemovalStrategy.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/IdentityRemovalStrategy.cs
index 08a4c46..f0ed6e6 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/IdentityRemovalStrategy.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/IdentityRemovalStrategy.cs
@@ -28,5 +28,13 @@
     /// </summary>
     public class IdentityRemovalStrategy : AbstractTraversalStrategy
     {
+        private const string JavaFqcn = OptimizationNamespace + nameof(IdentityRemovalStrategy);
+        
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="IdentityRemovalStrategy" /> class.
+        /// </summary>
+        public IdentityRemovalStrategy() : base(JavaFqcn)
+        {
+        }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/IncidentToAdjacentStrategy.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/IncidentToAdjacentStrategy.cs
index 75b98c2..f7da471 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/IncidentToAdjacentStrategy.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/IncidentToAdjacentStrategy.cs
@@ -29,5 +29,13 @@
     /// </summary>
     public class IncidentToAdjacentStrategy : AbstractTraversalStrategy
     {
+        private const string JavaFqcn = OptimizationNamespace + nameof(IncidentToAdjacentStrategy);
+        
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="IncidentToAdjacentStrategy" /> class.
+        /// </summary>
+        public IncidentToAdjacentStrategy() : base(JavaFqcn)
+        {
+        }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/InlineFilterStrategy.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/InlineFilterStrategy.cs
index 8eade84..0de2ef9 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/InlineFilterStrategy.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/InlineFilterStrategy.cs
@@ -28,5 +28,13 @@
     /// </summary>
     public class InlineFilterStrategy : AbstractTraversalStrategy
     {
+        private const string JavaFqcn = OptimizationNamespace + nameof(InlineFilterStrategy);
+        
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="InlineFilterStrategy" /> class.
+        /// </summary>
+        public InlineFilterStrategy() : base(JavaFqcn)
+        {
+        }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/LazyBarrierStrategy.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/LazyBarrierStrategy.cs
index b5cac4a..22f2dd6 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/LazyBarrierStrategy.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/LazyBarrierStrategy.cs
@@ -29,5 +29,13 @@
     /// </summary>
     public class LazyBarrierStrategy : AbstractTraversalStrategy
     {
+        private const string JavaFqcn = OptimizationNamespace + nameof(LazyBarrierStrategy);
+        
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="LazyBarrierStrategy" /> class.
+        /// </summary>
+        public LazyBarrierStrategy() : base(JavaFqcn)
+        {
+        }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/MatchPredicateStrategy.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/MatchPredicateStrategy.cs
index d535963..7560b71 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/MatchPredicateStrategy.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/MatchPredicateStrategy.cs
@@ -28,5 +28,13 @@
     /// </summary>
     public class MatchPredicateStrategy : AbstractTraversalStrategy
     {
+        private const string JavaFqcn = OptimizationNamespace + nameof(MatchPredicateStrategy);
+        
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="MatchPredicateStrategy" /> class.
+        /// </summary>
+        public MatchPredicateStrategy() : base(JavaFqcn)
+        {
+        }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/OrderLimitStrategy.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/OrderLimitStrategy.cs
index c8b4ec4..4afe08a 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/OrderLimitStrategy.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/OrderLimitStrategy.cs
@@ -26,6 +26,11 @@
 #pragma warning disable 1591
     public class OrderLimitStrategy : AbstractTraversalStrategy
     {
+        private const string JavaFqcn = OptimizationNamespace + nameof(OrderLimitStrategy);
+        
+        public OrderLimitStrategy() : base(JavaFqcn)
+        {
+        }
     }
 #pragma warning restore 1591
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/PathProcessorStrategy.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/PathProcessorStrategy.cs
index 2c8e106..cafa62a 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/PathProcessorStrategy.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/PathProcessorStrategy.cs
@@ -28,5 +28,13 @@
     /// </summary>
     public class PathProcessorStrategy : AbstractTraversalStrategy
     {
+        private const string JavaFqcn = OptimizationNamespace + nameof(PathProcessorStrategy);
+        
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="PathProcessorStrategy" /> class.
+        /// </summary>
+        public PathProcessorStrategy() : base(JavaFqcn)
+        {
+        }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/PathRetractionStrategy.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/PathRetractionStrategy.cs
index 03978e7..b9d44aa 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/PathRetractionStrategy.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/PathRetractionStrategy.cs
@@ -26,6 +26,11 @@
 #pragma warning disable 1591
     public class PathRetractionStrategy : AbstractTraversalStrategy
     {
+        private const string JavaFqcn = OptimizationNamespace + nameof(PathRetractionStrategy);
+        
+        public PathRetractionStrategy() : base(JavaFqcn)
+        {
+        }
     }
 #pragma warning restore 1591
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/RangeByIsCountStrategy.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/RangeByIsCountStrategy.cs
index e3024bc..b0c97d2 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/RangeByIsCountStrategy.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/RangeByIsCountStrategy.cs
@@ -28,5 +28,13 @@
     /// </summary>
     public class RangeByIsCountStrategy : AbstractTraversalStrategy
     {
+        private const string JavaFqcn = OptimizationNamespace + nameof(RangeByIsCountStrategy);
+        
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="RangeByIsCountStrategy" /> class.
+        /// </summary>
+        public RangeByIsCountStrategy() : base(JavaFqcn)
+        {
+        }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/RepeatUnrollStrategy.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/RepeatUnrollStrategy.cs
index b9e3fc2..57d5836 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/RepeatUnrollStrategy.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Optimization/RepeatUnrollStrategy.cs
@@ -26,6 +26,11 @@
 #pragma warning disable 1591
     public class RepeatUnrollStrategy : AbstractTraversalStrategy
     {
+        private const string JavaFqcn = OptimizationNamespace + nameof(RepeatUnrollStrategy);
+        
+        public RepeatUnrollStrategy() : base(JavaFqcn)
+        {
+        }
     }
 #pragma warning restore 1591
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Verification/EdgeLabelVerificationStrategy.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Verification/EdgeLabelVerificationStrategy.cs
index a76751a..18a5b78 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Verification/EdgeLabelVerificationStrategy.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Verification/EdgeLabelVerificationStrategy.cs
@@ -28,10 +28,12 @@
     /// </summary>
     public class EdgeLabelVerificationStrategy : AbstractTraversalStrategy
     {
+        private const string JavaFqcn = VerificationNamespace + nameof(EdgeLabelVerificationStrategy);
+
         /// <summary>
         ///     Initializes a new instance of the <see cref="EdgeLabelVerificationStrategy" /> class.
         /// </summary>
-        public EdgeLabelVerificationStrategy()
+        public EdgeLabelVerificationStrategy() : base(JavaFqcn)
         {
         }
 
@@ -41,6 +43,7 @@
         /// <param name="logWarning">Constrains vertices for the <see cref="ITraversal" />.</param>
         /// <param name="throwException">Constrains edges for the <see cref="ITraversal" />.</param>
         public EdgeLabelVerificationStrategy(bool logWarning = false, bool throwException = false)
+            : this()
         {
             Configuration["logWarning"] = logWarning;
             Configuration["throwException"] = throwException;
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Verification/LambdaRestrictionStrategy.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Verification/LambdaRestrictionStrategy.cs
index 0f488ab..732076e 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Verification/LambdaRestrictionStrategy.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Verification/LambdaRestrictionStrategy.cs
@@ -28,5 +28,13 @@
     /// </summary>
     public class LambdaRestrictionStrategy : AbstractTraversalStrategy
     {
+        private const string JavaFqcn = VerificationNamespace + nameof(LambdaRestrictionStrategy);
+        
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="LambdaRestrictionStrategy" /> class.
+        /// </summary>
+        public LambdaRestrictionStrategy() : base(JavaFqcn)
+        {
+        }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Verification/ReadOnlyStrategy.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Verification/ReadOnlyStrategy.cs
index a703e18..db3d9d9 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Verification/ReadOnlyStrategy.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Verification/ReadOnlyStrategy.cs
@@ -28,5 +28,13 @@
     /// </summary>
     public class ReadOnlyStrategy : AbstractTraversalStrategy
     {
+        private const string JavaFqcn = VerificationNamespace + nameof(ReadOnlyStrategy);
+        
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="ReadOnlyStrategy" /> class.
+        /// </summary>
+        public ReadOnlyStrategy() : base(JavaFqcn)
+        {
+        }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Verification/ReservedKeysVerificationStrategy.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Verification/ReservedKeysVerificationStrategy.cs
index 8ecc753..eccae0d 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Verification/ReservedKeysVerificationStrategy.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Strategy/Verification/ReservedKeysVerificationStrategy.cs
@@ -31,10 +31,12 @@
     /// </summary>
     public class ReservedKeysVerificationStrategy : AbstractTraversalStrategy
     {
+        private const string JavaFqcn = VerificationNamespace + nameof(ReservedKeysVerificationStrategy);
+
         /// <summary>
         ///     Initializes a new instance of the <see cref="ReservedKeysVerificationStrategy" /> class.
         /// </summary>
-        public ReservedKeysVerificationStrategy()
+        public ReservedKeysVerificationStrategy() : base(JavaFqcn)
         {
         }
 
@@ -44,7 +46,9 @@
         /// <param name="logWarning">Write a warning to the configured log on the server if a reserved key is used.</param>
         /// <param name="throwException">Throw an exception if a reserved key is used.</param>
         /// <param name="keys">List of keys to define as reserved. If not set then the defaults are used.</param>
-        public ReservedKeysVerificationStrategy(bool logWarning = false, bool throwException = false, List<string> keys = null)
+        public ReservedKeysVerificationStrategy(bool logWarning = false, bool throwException = false,
+            List<string> keys = null)
+            : this()
         {
             Configuration["logWarning"] = logWarning;
             Configuration["throwException"] = throwException;
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/StringBasedLambda.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/StringBasedLambda.cs
index 71a4651..69f8030 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/StringBasedLambda.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/StringBasedLambda.cs
@@ -28,24 +28,18 @@
     internal class StringBasedLambda : ILambda
     {
         private const int DefaultArgument = -1;
-        private int _arguments;
 
         public StringBasedLambda(string expression, string language)
         {
             LambdaExpression = expression;
             Language = language;
-            _arguments = DefaultArgument;
         }
 
         public string LambdaExpression { get; }
 
         public string Language { get; }
 
-        public int Arguments
-        {
-            get => _arguments;
-            protected set => _arguments = value;
-        }
+        public int Arguments { get; protected set; } = DefaultArgument;
     }
 
     internal class GroovyStringBasedLambda : StringBasedLambda
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/T.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/T.cs
index 80ca0ec..e688e8d 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/T.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/T.cs
@@ -21,7 +21,6 @@
 
 #endregion
 
-// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml
 using System;
 using System.Collections.Generic;
 
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/TextP.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/TextP.cs
index 3047f75..a77f206 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/TextP.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/TextP.cs
@@ -21,12 +21,8 @@
 
 #endregion
 
-// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml
-using System;
-using System.Collections;
 using System.Collections.Generic;
 using System.Linq;
-using System.Reflection;
 
 namespace Gremlin.Net.Process.Traversal
 {
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/WithOptions.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/WithOptions.cs
index c20c59a..0229d4c 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/WithOptions.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/WithOptions.cs
@@ -21,7 +21,6 @@
 
 #endregion
 
-// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml
 using System;
 using System.Collections;
 using System.Collections.Generic;
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs
index 9bd0b14..fa1c027 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs
@@ -24,7 +24,6 @@
 using System.Collections.Generic;
 using Gremlin.Net.Structure;
 
-// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml
 namespace Gremlin.Net.Process.Traversal
 {
     /// <summary>
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/DataType.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/DataType.cs
new file mode 100644
index 0000000..cb309c2
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/DataType.cs
@@ -0,0 +1,159 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary
+{
+    /// <summary>
+    /// Represents a GraphBinary data type.
+    /// </summary>
+    public class DataType : IEquatable<DataType>
+    {
+#pragma warning disable 1591
+        public static readonly DataType Int = new DataType(0x01);
+        public static readonly DataType Long = new DataType(0x02);
+        public static readonly DataType String = new DataType(0x03);
+        public static readonly DataType Date = new DataType(0x04);
+        public static readonly DataType Timestamp = new DataType(0x05);
+        public static readonly DataType Class = new DataType(0x06);
+        public static readonly DataType Double = new DataType(0x07);
+        public static readonly DataType Float = new DataType(0x08);
+        public static readonly DataType List = new DataType(0x09);
+        public static readonly DataType Map = new DataType(0X0A);
+        public static readonly DataType Set = new DataType(0X0B);
+        public static readonly DataType Uuid = new DataType(0X0C);
+        public static readonly DataType Edge = new DataType(0x0D);
+        public static readonly DataType Path = new DataType(0x0E);
+        public static readonly DataType Property = new DataType(0x0F);
+        
+        public static readonly DataType Vertex = new DataType(0x11);
+        public static readonly DataType VertexProperty = new DataType(0x12);
+        public static readonly DataType Barrier = new DataType(0x13);
+        public static readonly DataType Binding = new DataType(0x14);
+        public static readonly DataType Bytecode = new DataType(0x15);
+        public static readonly DataType Cardinality = new DataType(0x16);
+        public static readonly DataType Column = new DataType(0x17);
+        public static readonly DataType Direction = new DataType(0x18);
+        public static readonly DataType Operator = new DataType(0x19);
+        public static readonly DataType Order = new DataType(0x1A);
+        public static readonly DataType Pick = new DataType(0x1B);
+        public static readonly DataType Pop = new DataType(0x1C);
+        public static readonly DataType Lambda = new DataType(0x1D);
+        public static readonly DataType P = new DataType(0x1E);
+        public static readonly DataType Scope = new DataType(0x1F);
+        public static readonly DataType T = new DataType(0x20);
+        public static readonly DataType Traverser = new DataType(0x21);
+        public static readonly DataType BigDecimal = new DataType(0x22);
+        public static readonly DataType BigInteger = new DataType(0x23);
+        public static readonly DataType Byte = new DataType(0x24);
+        public static readonly DataType ByteBuffer = new DataType(0x25);
+        public static readonly DataType Short = new DataType(0x26);
+        public static readonly DataType Boolean = new DataType(0x27);
+        public static readonly DataType TextP = new DataType(0x28);
+        public static readonly DataType TraversalStrategy = new DataType(0x29);
+        public static readonly DataType BulkSet = new DataType(0x2A);
+        // TODO: Support metrics and traversal metrics
+        public static readonly DataType Char = new DataType(0x80);
+        public static readonly DataType Duration = new DataType(0x81);
+#pragma warning restore 1591
+
+        /// <summary>
+        /// A null value for an unspecified Object value.
+        /// </summary>
+        public static readonly DataType UnspecifiedNull = new DataType(0xFE);
+
+        private DataType(int code)
+        {
+            TypeCode = (byte) code;
+        }
+        
+        /// <summary>
+        ///     Gets the type code of this data type.
+        /// </summary>
+        public byte TypeCode { get; }
+
+        /// <summary>
+        /// Creates a new <see cref="DataType"/> instance for the given type code.
+        /// </summary>
+        public static DataType FromTypeCode(int code)
+        {
+            return new DataType(code);
+        }
+
+        /// <inheritdoc />
+        public bool Equals(DataType other)
+        {
+            if (ReferenceEquals(null, other)) return false;
+            if (ReferenceEquals(this, other)) return true;
+            return TypeCode == other.TypeCode;
+        }
+
+        /// <inheritdoc />
+        public override bool Equals(object obj)
+        {
+            if (ReferenceEquals(null, obj)) return false;
+            if (ReferenceEquals(this, obj)) return true;
+            if (obj.GetType() != GetType()) return false;
+            return Equals((DataType) obj);
+        }
+
+        /// <inheritdoc />
+        public override int GetHashCode()
+        {
+            return TypeCode.GetHashCode();
+        }
+
+        /// <summary>
+        /// Determines whether two specified <see cref="DataType"/> have the same values.
+        /// </summary>
+        public static bool operator ==(DataType first, DataType second)
+        {
+            if (ReferenceEquals(null, first))
+            {
+                if (ReferenceEquals(null, second))
+                {
+                    return true;
+                }
+
+                return false;
+            }
+
+            return first.Equals(second);
+        }
+
+        /// <summary>
+        /// Determines whether two specified <see cref="DataType"/> have different values.
+        /// </summary>
+        public static bool operator !=(DataType first, DataType second)
+        {
+            return !(first == second);
+        }
+
+        /// <inheritdoc />
+        public override string ToString()
+        {
+            return $"DataType{{ TypeCode = {TypeCode} }}";
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/GraphBinaryMessageSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/GraphBinaryMessageSerializer.cs
new file mode 100644
index 0000000..2b56935
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/GraphBinaryMessageSerializer.cs
@@ -0,0 +1,75 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Threading.Tasks;
+using Gremlin.Net.Driver;
+using Gremlin.Net.Driver.Messages;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary
+{
+    /// <summary>
+    ///     Serializes data to and from Gremlin Server in GraphBinary format.
+    /// </summary>
+    public class GraphBinaryMessageSerializer : IMessageSerializer
+    {
+        private const string MimeType = SerializationTokens.GraphBinary1MimeType;
+        private static readonly byte[] Header = Encoding.UTF8.GetBytes(MimeType);
+        
+        private readonly GraphBinaryReader _reader;
+        private readonly GraphBinaryWriter _writer;
+        private readonly RequestMessageSerializer _requestSerializer = new RequestMessageSerializer();
+        private readonly ResponseMessageSerializer _responseSerializer = new ResponseMessageSerializer();
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="GraphBinaryMessageSerializer" /> class.
+        /// </summary>
+        /// <param name="reader">The <see cref="GraphBinaryReader"/> used to deserialize from GraphBinary.</param>
+        /// <param name="writer">The <see cref="GraphBinaryWriter"/> used to serialize to GraphBinary.</param>
+        public GraphBinaryMessageSerializer(GraphBinaryReader reader = null, GraphBinaryWriter writer = null)
+        {
+            _reader = reader ?? new GraphBinaryReader();
+            _writer = writer ?? new GraphBinaryWriter();
+        }
+
+        /// <inheritdoc />
+        public async Task<byte[]> SerializeMessageAsync(RequestMessage requestMessage)
+        {
+            var stream = new MemoryStream();
+            await stream.WriteByteAsync((byte) Header.Length).ConfigureAwait(false);
+            await stream.WriteAsync(Header).ConfigureAwait(false);
+            await _requestSerializer.WriteValueAsync(requestMessage, stream, _writer).ConfigureAwait(false);
+            var bytes = stream.ToArray();
+            return bytes;
+        }
+
+        /// <inheritdoc />
+        public async Task<ResponseMessage<List<object>>> DeserializeMessageAsync(byte[] message)
+        {
+            var stream = new MemoryStream(message);
+            return await _responseSerializer.ReadValueAsync(stream, _reader).ConfigureAwait(false);
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/GraphBinaryReader.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/GraphBinaryReader.cs
new file mode 100644
index 0000000..deaf31a
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/GraphBinaryReader.cs
@@ -0,0 +1,68 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System.IO;
+using System.Threading.Tasks;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary
+{
+    /// <summary>
+    /// Allows to deserialize objects from GraphBinary.
+    /// </summary>
+    public class GraphBinaryReader
+    {
+        private readonly TypeSerializerRegistry _registry = new TypeSerializerRegistry();
+        
+        /// <summary>
+        /// Reads only the value for a specific type <typeparamref name="T"/>.
+        /// </summary>
+        /// <param name="stream">The GraphBinary data to parse.</param>
+        /// <param name="nullable">Whether or not the value can be null.</param>
+        /// <typeparam name="T">The type of the object to read.</typeparam>
+        /// <returns>The read value.</returns>
+        public async Task<object> ReadValueAsync<T>(Stream stream, bool nullable)
+        {
+            var typedSerializer = _registry.GetSerializerFor(typeof(T));
+            return await typedSerializer.ReadValueAsync(stream, this, nullable).ConfigureAwait(false);
+        }
+        
+        /// <summary>
+        /// Reads the type code, information and value with fully-qualified format.
+        /// </summary>
+        /// <param name="stream">The GraphBinary data to parse.</param>
+        /// <returns>The read value.</returns>
+        public async Task<object> ReadAsync(Stream stream)
+        {
+            var type = DataType.FromTypeCode(await stream.ReadByteAsync().ConfigureAwait(false));
+
+            if (type == DataType.UnspecifiedNull)
+            {
+                await stream.ReadByteAsync().ConfigureAwait(false); // read value byte to advance the index
+                return default; // should be null (TODO?)
+            }
+
+            var typedSerializer = _registry.GetSerializerFor(type);
+            return await typedSerializer.ReadAsync(stream, this).ConfigureAwait(false);
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/GraphBinaryWriter.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/GraphBinaryWriter.cs
new file mode 100644
index 0000000..e1eec8f
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/GraphBinaryWriter.cs
@@ -0,0 +1,112 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System.IO;
+using System.Threading.Tasks;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary
+{
+    /// <summary>
+    /// Allows to serialize objects to GraphBinary.
+    /// </summary>
+    public class GraphBinaryWriter
+    {
+        private const byte ValueFlagNull = 1;
+        private const byte ValueFlagNone = 0;
+
+        /// <summary>
+        /// A <see cref="byte"/> representing the version of the GraphBinary specification.
+        /// </summary>
+        public const byte VersionByte = 0x81;
+
+        private static readonly byte[] UnspecifiedNullBytes = {DataType.UnspecifiedNull.TypeCode, 0x01};
+
+        private readonly TypeSerializerRegistry _registry = new TypeSerializerRegistry();
+
+        /// <summary>
+        /// Writes a value without including type information.
+        /// </summary>
+        /// <param name="value">The value to write.</param>
+        /// <param name="stream">The stream to write to.</param>
+        /// <param name="nullable">Whether or not the value can be null.</param>
+        /// <returns>A task that represents the asynchronous write operation.</returns>
+        public async Task WriteValueAsync(object value, Stream stream, bool nullable)
+        {
+            if (value == null)
+            {
+                if (!nullable)
+                {
+                    throw new IOException("Unexpected null value when nullable is false");
+                }
+
+                await WriteValueFlagNullAsync(stream).ConfigureAwait(false);
+                return;
+            }
+            
+            var valueType = value.GetType();
+            var serializer = _registry.GetSerializerFor(valueType);
+            await serializer.WriteValueAsync(value, stream, this, nullable).ConfigureAwait(false);
+        }
+        
+        /// <summary>
+        /// Writes an object in fully-qualified format, containing {type_code}{type_info}{value_flag}{value}.
+        /// </summary>
+        /// <param name="value">The value to write.</param>
+        /// <param name="stream">The stream to write to.</param>
+        /// <returns>A task that represents the asynchronous write operation.</returns>
+        public async Task WriteAsync(object value, Stream stream)
+        {
+            if (value == null)
+            {
+                await stream.WriteAsync(UnspecifiedNullBytes).ConfigureAwait(false);
+                return;
+            }
+
+            var valueType = value.GetType();
+            var serializer = _registry.GetSerializerFor(valueType);
+            await stream.WriteByteAsync(serializer.DataType.TypeCode).ConfigureAwait(false);
+            await serializer.WriteAsync(value, stream, this).ConfigureAwait(false);
+        }
+        
+        /// <summary>
+        /// Writes a single byte representing the null value_flag.
+        /// </summary>
+        /// <param name="stream">The stream to write to.</param>
+        /// <returns>A task that represents the asynchronous write operation.</returns>
+        public async Task WriteValueFlagNullAsync(Stream stream)
+        {
+            await stream.WriteByteAsync(ValueFlagNull).ConfigureAwait(false);
+        }
+
+        /// <summary>
+        /// Writes a single byte with value 0, representing an unset value_flag.
+        /// </summary>
+        /// <param name="stream">The stream to write to.</param>
+        /// <returns>A task that represents the asynchronous write operation.</returns>
+        public async Task WriteValueFlagNoneAsync(Stream stream) {
+            await stream.WriteByteAsync(ValueFlagNone).ConfigureAwait(false);
+        }
+
+        
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/ITypeSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/ITypeSerializer.cs
new file mode 100644
index 0000000..fd21f52
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/ITypeSerializer.cs
@@ -0,0 +1,75 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System.IO;
+using System.Threading.Tasks;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary
+{
+    /// <summary>
+    /// Represents a serializer for a certain type.
+    /// </summary>
+    public interface ITypeSerializer
+    {
+        /// <summary>
+        /// Gets the <see cref="DataType"/> that supported by this serializer.
+        /// </summary>
+        DataType DataType { get; }
+
+        /// <summary>
+        /// Writes the type code, information and value to a stream.
+        /// </summary>
+        /// <param name="value">The value to write.</param>
+        /// <param name="stream">The stream to write to.</param>
+        /// <param name="writer">A <see cref="GraphBinaryWriter"/> that can be used to write nested values.</param>
+        /// <returns>A task that represents the asynchronous write operation.</returns>
+        Task WriteAsync(object value, Stream stream, GraphBinaryWriter writer);
+
+        /// <summary>
+        /// Writes the value to a stream, composed by the value flag and the sequence of bytes.
+        /// </summary>
+        /// <param name="value">The value to write.</param>
+        /// <param name="stream">The stream to write to.</param>
+        /// <param name="writer">A <see cref="GraphBinaryWriter"/> that can be used to write nested values.</param>
+        /// <param name="nullable">Whether or not the value can be null.</param>
+        /// <returns>A task that represents the asynchronous write operation.</returns>
+        Task WriteValueAsync(object value, Stream stream, GraphBinaryWriter writer, bool nullable);
+
+        /// <summary>
+        /// Reads the type information and value from the stream.
+        /// </summary>
+        /// <param name="stream">The GraphBinary data to parse.</param>
+        /// <param name="reader">A <see cref="GraphBinaryReader"/> that can be used to read nested values.</param>
+        /// <returns>The read value.</returns>
+        Task<object> ReadAsync(Stream stream, GraphBinaryReader reader);
+
+        /// <summary>
+        /// Reads the value from the stream (not the type information).
+        /// </summary>
+        /// <param name="stream">The GraphBinary data to parse.</param>
+        /// <param name="reader">A <see cref="GraphBinaryReader"/> that can be used to read nested values.</param>
+        /// <param name="nullable">Whether or not the value can be null.</param>
+        /// <returns>The read value.</returns>
+        Task<object> ReadValueAsync(Stream stream, GraphBinaryReader reader, bool nullable);
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/RequestMessageSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/RequestMessageSerializer.cs
new file mode 100644
index 0000000..e9e22f3
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/RequestMessageSerializer.cs
@@ -0,0 +1,51 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System.IO;
+using System.Threading.Tasks;
+using Gremlin.Net.Driver.Messages;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary
+{
+    /// <summary>
+    /// Allows to serialize a <see cref="RequestMessage"/>.
+    /// </summary>
+    public class RequestMessageSerializer
+    {
+        /// <summary>
+        /// Write the request message to a stream.
+        /// </summary>
+        /// <param name="requestMessage">The message to serialize.</param>
+        /// <param name="stream">The stream to write to.</param>
+        /// <param name="writer">A <see cref="GraphBinaryWriter"/> that can be used to write nested values.</param>
+        /// <returns>A task that represents the asynchronous write operation.</returns>
+        public async Task WriteValueAsync(RequestMessage requestMessage, MemoryStream stream, GraphBinaryWriter writer)
+        {
+            await stream.WriteByteAsync(GraphBinaryWriter.VersionByte).ConfigureAwait(false);
+            await writer.WriteValueAsync(requestMessage.RequestId, stream, false).ConfigureAwait(false);
+            await writer.WriteValueAsync(requestMessage.Operation, stream, false).ConfigureAwait(false);
+            await writer.WriteValueAsync(requestMessage.Processor, stream, false).ConfigureAwait(false);
+            await writer.WriteValueAsync(requestMessage.Arguments, stream, false).ConfigureAwait(false);
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/ResponseMessageSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/ResponseMessageSerializer.cs
new file mode 100644
index 0000000..c31ab5f
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/ResponseMessageSerializer.cs
@@ -0,0 +1,82 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading.Tasks;
+using Gremlin.Net.Driver.Messages;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary
+{
+    /// <summary>
+    /// Allows to deserialize a <see cref="ResponseMessage{T}"/>.
+    /// </summary>
+    public class ResponseMessageSerializer
+    {
+        /// <summary>
+        /// Reads a response message from the stream.
+        /// </summary>
+        /// <param name="stream">The GraphBinary data to parse.</param>
+        /// <param name="reader">A <see cref="GraphBinaryReader"/> that can be used to read nested values.</param>
+        /// <returns>The read response message.</returns>
+        public async Task<ResponseMessage<List<object>>> ReadValueAsync(MemoryStream stream, GraphBinaryReader reader)
+        {
+            var version = await stream.ReadByteAsync().ConfigureAwait(false) & 0xff;
+
+            if (version >> 7 != 1)
+            {
+                // This is an indication that the response stream was incorrectly built
+                // Or the stream offsets are wrong
+                throw new IOException("The most significant bit should be set according to the format");
+            }
+
+            var requestId = (Guid?) await reader.ReadValueAsync<Guid>(stream, true).ConfigureAwait(false);
+            var code = (ResponseStatusCode) await reader.ReadValueAsync<int>(stream, false).ConfigureAwait(false);
+            var message = (string) await reader.ReadValueAsync<string>(stream, true).ConfigureAwait(false);
+            var dictObj = await reader
+                .ReadValueAsync<Dictionary<string, object>>(stream, false).ConfigureAwait(false);
+            var attributes = (Dictionary<string, object>) dictObj;
+
+            var status = new ResponseStatus
+            {
+                Code = code,
+                Message = message,
+                Attributes = attributes
+            };
+            var result = new ResponseResult<List<object>>
+            {
+                Meta = (Dictionary<string, object>) await reader
+                    .ReadValueAsync<Dictionary<string, object>>(stream, false).ConfigureAwait(false),
+                Data = (List<object>) await reader.ReadAsync(stream).ConfigureAwait(false)
+            };
+
+            return new ResponseMessage<List<object>>
+            {
+                RequestId = requestId,
+                Status = status,
+                Result = result
+            };
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/StreamExtensions.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/StreamExtensions.cs
new file mode 100644
index 0000000..c407c21
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/StreamExtensions.cs
@@ -0,0 +1,144 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System;
+using System.IO;
+using System.Threading.Tasks;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary
+{
+    internal static class StreamExtensions
+    {
+        public static async Task WriteByteAsync(this Stream stream, byte value)
+        {
+            await stream.WriteAsync(new[] {value}, 0, 1).ConfigureAwait(false);
+        }
+        
+        public static async Task<byte> ReadByteAsync(this Stream stream)
+        {
+            var readBuffer = new byte[1];
+            await stream.ReadAsync(readBuffer, 0, 1);
+            return readBuffer[0];
+        }
+
+        public static async Task WriteIntAsync(this Stream stream, int value)
+        {
+            var bytes = BitConverter.GetBytes(value);
+            await stream.WriteAsync(new[] {bytes[3], bytes[2], bytes[1], bytes[0]}, 0, 4).ConfigureAwait(false);
+        }
+        
+        public static async Task<int> ReadIntAsync(this Stream stream)
+        {
+            var bytes = new byte[4];
+            await stream.ReadAsync(bytes, 0, 4).ConfigureAwait(false);
+            return BitConverter.ToInt32(new []{bytes[3], bytes[2], bytes[1], bytes[0]}, 0);
+        }
+        
+        public static async Task WriteLongAsync(this Stream stream, long value)
+        {
+            var bytes = BitConverter.GetBytes(value);
+            await stream
+                .WriteAsync(new[] {bytes[7], bytes[6], bytes[5], bytes[4], bytes[3], bytes[2], bytes[1], bytes[0]}, 0,
+                    8).ConfigureAwait(false);
+        }
+        
+        public static async Task<long> ReadLongAsync(this Stream stream)
+        {
+            var bytes = new byte[8];
+            await stream.ReadAsync(bytes, 0, 8).ConfigureAwait(false);
+            return BitConverter.ToInt64(
+                new[] {bytes[7], bytes[6], bytes[5], bytes[4], bytes[3], bytes[2], bytes[1], bytes[0]}, 0);
+        }
+        
+        public static async Task WriteFloatAsync(this Stream stream, float value)
+        {
+            var bytes = BitConverter.GetBytes(value);
+            await stream.WriteAsync(new[] {bytes[3], bytes[2], bytes[1], bytes[0]}, 0, 4).ConfigureAwait(false);
+        }
+        
+        public static async Task<float> ReadFloatAsync(this Stream stream)
+        {
+            var bytes = new byte[4];
+            await stream.ReadAsync(bytes, 0, 4).ConfigureAwait(false);
+            return BitConverter.ToSingle(new []{bytes[3], bytes[2], bytes[1], bytes[0]}, 0);
+        }
+        
+        public static async Task WriteDoubleAsync(this Stream stream, double value)
+        {
+            var bytes = BitConverter.GetBytes(value);
+            await stream
+                .WriteAsync(new[] {bytes[7], bytes[6], bytes[5], bytes[4], bytes[3], bytes[2], bytes[1], bytes[0]}, 0,
+                    8).ConfigureAwait(false);
+        }
+        
+        public static async Task<double> ReadDoubleAsync(this Stream stream)
+        {
+            var bytes = new byte[8];
+            await stream.ReadAsync(bytes, 0, 8).ConfigureAwait(false);
+            return BitConverter.ToDouble(
+                new[] {bytes[7], bytes[6], bytes[5], bytes[4], bytes[3], bytes[2], bytes[1], bytes[0]}, 0);
+        }
+        
+        public static async Task WriteShortAsync(this Stream stream, short value)
+        {
+            var bytes = BitConverter.GetBytes(value);
+            await stream.WriteAsync(new[] {bytes[1], bytes[0]}, 0, 2).ConfigureAwait(false);
+        }
+        
+        public static async Task<short> ReadShortAsync(this Stream stream)
+        {
+            var bytes = new byte[2];
+            await stream.ReadAsync(bytes, 0, 2).ConfigureAwait(false);
+            return BitConverter.ToInt16(new []{bytes[1], bytes[0]}, 0);
+        }
+        
+        public static async Task WriteBoolAsync(this Stream stream, bool value)
+        {
+            await stream.WriteByteAsync((byte) (value ? 1 : 0)).ConfigureAwait(false);
+        }
+        
+        public static async Task<bool> ReadBoolAsync(this Stream stream)
+        {
+            var b = await stream.ReadByteAsync().ConfigureAwait(false);
+            switch (b)
+            {
+                case 1:
+                    return true;
+                case 0:
+                    return false;
+                default:
+                    throw new IOException($"Cannot read byte {b} as a boolean.");
+            }
+        }
+        
+        public static async Task WriteAsync(this Stream stream, byte[] value)
+        {
+            await stream.WriteAsync(value, 0, value.Length).ConfigureAwait(false);
+        }
+
+        public static async Task ReadAsync(this Stream stream, byte[] buffer)
+        {
+            await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/TypeSerializerRegistry.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/TypeSerializerRegistry.cs
new file mode 100644
index 0000000..efa1699
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/TypeSerializerRegistry.cs
@@ -0,0 +1,224 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Numerics;
+using Gremlin.Net.Process.Traversal;
+using Gremlin.Net.Process.Traversal.Strategy;
+using Gremlin.Net.Structure.IO.GraphBinary.Types;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary
+{
+    /// <summary>
+    /// Provides GraphBinary serializers for different types.
+    /// </summary>
+    public class TypeSerializerRegistry
+    {
+        private static readonly Dictionary<Type, ITypeSerializer> SerializerByType =
+            new Dictionary<Type, ITypeSerializer>
+            {
+                {typeof(int), SingleTypeSerializers.IntSerializer},
+                {typeof(long), SingleTypeSerializers.LongSerializer},
+                {typeof(string), new StringSerializer()},
+                {typeof(DateTimeOffset), DateTimeOffsetSerializer.DateSerializer},
+                {typeof(GremlinType), new ClassSerializer()},
+                {typeof(Type), new TypeSerializer()},
+                {typeof(double), SingleTypeSerializers.DoubleSerializer},
+                {typeof(float), SingleTypeSerializers.FloatSerializer},
+                {typeof(Guid), new UuidSerializer()},
+                {typeof(Edge), new EdgeSerializer()},
+                {typeof(Path), new PathSerializer()},
+                {typeof(Property), new PropertySerializer()},
+                {typeof(Vertex), new VertexSerializer()},
+                {typeof(VertexProperty), new VertexPropertySerializer()},
+                {typeof(Barrier), EnumSerializers.BarrierSerializer},
+                {typeof(Binding), new BindingSerializer()},
+                {typeof(Bytecode), new BytecodeSerializer()},
+                {typeof(ITraversal), new TraversalSerializer()},
+                {typeof(Cardinality), EnumSerializers.CardinalitySerializer},
+                {typeof(Column), EnumSerializers.ColumnSerializer},
+                {typeof(Direction), EnumSerializers.DirectionSerializer},
+                {typeof(Operator), EnumSerializers.OperatorSerializer},
+                {typeof(Order), EnumSerializers.OrderSerializer},
+                {typeof(Pick), EnumSerializers.PickSerializer},
+                {typeof(Pop), EnumSerializers.PopSerializer},
+                {typeof(ILambda), new LambdaSerializer()},
+                {typeof(P), new PSerializer(DataType.P)},
+                {typeof(Scope), EnumSerializers.ScopeSerializer},
+                {typeof(T), EnumSerializers.TSerializer},
+                {typeof(Traverser), new TraverserSerializer()},
+                {typeof(decimal), new BigDecimalSerializer()},
+                {typeof(BigInteger), new BigIntegerSerializer()},
+                {typeof(byte), SingleTypeSerializers.ByteSerializer},
+                {typeof(byte[]), new ByteBufferSerializer()},
+                {typeof(short), SingleTypeSerializers.ShortSerializer},
+                {typeof(bool), SingleTypeSerializers.BooleanSerializer},
+                {typeof(TextP), new PSerializer(DataType.TextP)},
+                {typeof(AbstractTraversalStrategy), new TraversalStrategySerializer()},
+                {typeof(char), new CharSerializer()},
+                {typeof(TimeSpan), new DurationSerializer()},
+            };
+
+        private static readonly Dictionary<DataType, ITypeSerializer> SerializerByDataType =
+            new Dictionary<DataType, ITypeSerializer>
+            {
+                {DataType.Int, SingleTypeSerializers.IntSerializer},
+                {DataType.Long, SingleTypeSerializers.LongSerializer},
+                {DataType.String, new StringSerializer()},
+                {DataType.Date, DateTimeOffsetSerializer.DateSerializer},
+                {DataType.Timestamp, DateTimeOffsetSerializer.TimestampSerializer},
+                {DataType.Class, new ClassSerializer()},
+                {DataType.Double, SingleTypeSerializers.DoubleSerializer},
+                {DataType.Float, SingleTypeSerializers.FloatSerializer},
+                {DataType.List, new ListSerializer<object>()},
+                {DataType.Map, new MapSerializer<object, object>()},
+                {DataType.Set, new SetSerializer<HashSet<object>, object>()},
+                {DataType.Uuid, new UuidSerializer()},
+                {DataType.Edge, new EdgeSerializer()},
+                {DataType.Path, new PathSerializer()},
+                {DataType.Property, new PropertySerializer()},
+                {DataType.Vertex, new VertexSerializer()},
+                {DataType.VertexProperty, new VertexPropertySerializer()},
+                {DataType.Barrier, EnumSerializers.BarrierSerializer},
+                {DataType.Binding, new BindingSerializer()},
+                {DataType.Bytecode, new BytecodeSerializer()},
+                {DataType.Cardinality, EnumSerializers.CardinalitySerializer},
+                {DataType.Column, EnumSerializers.ColumnSerializer},
+                {DataType.Direction, EnumSerializers.DirectionSerializer},
+                {DataType.Operator, EnumSerializers.OperatorSerializer},
+                {DataType.Order, EnumSerializers.OrderSerializer},
+                {DataType.Pick, EnumSerializers.PickSerializer},
+                {DataType.Pop, EnumSerializers.PopSerializer},
+                {DataType.Lambda, new LambdaSerializer()},
+                {DataType.P, new PSerializer(DataType.P)},
+                {DataType.Scope, EnumSerializers.ScopeSerializer},
+                {DataType.T, EnumSerializers.TSerializer},
+                {DataType.Traverser, new TraverserSerializer()},
+                {DataType.BigDecimal, new BigDecimalSerializer()},
+                {DataType.BigInteger, new BigIntegerSerializer()},
+                {DataType.Byte, SingleTypeSerializers.ByteSerializer},
+                {DataType.ByteBuffer, new ByteBufferSerializer()},
+                {DataType.Short, SingleTypeSerializers.ShortSerializer},
+                {DataType.Boolean, SingleTypeSerializers.BooleanSerializer},
+                {DataType.TextP, new PSerializer(DataType.TextP)},
+                {DataType.TraversalStrategy, new TraversalStrategySerializer()},
+                {DataType.BulkSet, new BulkSetSerializer<List<object>>()},
+                {DataType.Char, new CharSerializer()},
+                {DataType.Duration, new DurationSerializer()},
+            };
+
+        /// <summary>
+        /// Gets a serializer for the given type of the value to be serialized.
+        /// </summary>
+        /// <param name="valueType">Type of the value to be serialized.</param>
+        /// <returns>A serializer for the provided type.</returns>
+        /// <exception cref="InvalidOperationException">Thrown when no serializer can be found for the type.</exception>
+        public ITypeSerializer GetSerializerFor(Type valueType)
+        {
+            if (SerializerByType.ContainsKey(valueType))
+            {
+                return SerializerByType[valueType];
+            }
+            
+            if (IsDictionaryType(valueType))
+            {
+                var dictKeyType = valueType.GetGenericArguments()[0];
+                var dictValueType = valueType.GetGenericArguments()[1];
+                var serializerType = typeof(MapSerializer<,>).MakeGenericType(dictKeyType, dictValueType);
+                var serializer = (ITypeSerializer) Activator.CreateInstance(serializerType);
+                SerializerByType[valueType] = serializer;
+                return serializer;
+            }
+
+            if (IsSetType(valueType))
+            {
+                var memberType = valueType.GetGenericArguments()[0];
+                var serializerType = typeof(SetSerializer<,>).MakeGenericType(valueType, memberType);
+                var serializer = (ITypeSerializer) Activator.CreateInstance(serializerType);
+                SerializerByType[valueType] = serializer;
+                return serializer;
+            }
+
+            if (valueType.IsArray)
+            {
+                var memberType = valueType.GetElementType();
+                var serializerType = typeof(ArraySerializer<>).MakeGenericType(memberType);
+                var serializer = (ITypeSerializer) Activator.CreateInstance(serializerType);
+                SerializerByType[valueType] = serializer;
+                return serializer;
+            }
+
+            if (IsListType(valueType))
+            {
+                var memberType = valueType.GetGenericArguments()[0];
+                var serializerType = typeof(ListSerializer<>).MakeGenericType(memberType);
+                var serializer = (ITypeSerializer) Activator.CreateInstance(serializerType);
+                SerializerByType[valueType] = serializer;
+                return serializer;
+            }
+
+            foreach (var supportedType in SerializerByType.Keys)
+            {
+                if (supportedType.IsAssignableFrom(valueType))
+                {
+                    var serializer = SerializerByType[supportedType];
+                    SerializerByType[valueType] = serializer;
+                    return serializer;
+                }
+            }
+
+            throw new InvalidOperationException($"No serializer found for type ${valueType}.");
+        }
+
+        private static bool IsDictionaryType(Type type)
+        {
+            return type.IsConstructedGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>);
+        }
+        
+        private static bool IsSetType(Type type)
+        {
+            return type.GetInterfaces().Any(implementedInterface => implementedInterface.IsConstructedGenericType &&
+                                                                    implementedInterface.GetGenericTypeDefinition() ==
+                                                                    typeof(ISet<>));
+        }
+
+        private static bool IsListType(Type type)
+        {
+            return type.GetInterfaces().Any(implementedInterface => implementedInterface.IsConstructedGenericType &&
+                                                                    implementedInterface.GetGenericTypeDefinition() ==
+                                                                    typeof(IList<>));
+        }
+        
+        /// <summary>
+        /// Gets a serializer for the given GraphBinary type.
+        /// </summary>
+        /// <param name="type">The GraphBinary type that should be (de)serialized.</param>
+        /// <returns>A serializer for the provided GraphBinary type.</returns>
+        public ITypeSerializer GetSerializerFor(DataType type)
+        {
+            return SerializerByDataType[type];
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ArraySerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ArraySerializer.cs
new file mode 100644
index 0000000..fecac6d
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ArraySerializer.cs
@@ -0,0 +1,62 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System;
+using System.IO;
+using System.Threading.Tasks;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary.Types
+{
+    /// <summary>
+    /// A serializer that serializes .NET arrays to GraphBinary lists.
+    /// </summary>
+    /// <typeparam name="TMember">The type of elements in the array.</typeparam>
+    public class ArraySerializer<TMember> : SimpleTypeSerializer<TMember[]>
+    {
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="ArraySerializer{TMember}" /> class.
+        /// </summary>
+        public ArraySerializer() : base(DataType.List)
+        {
+        }
+
+        /// <inheritdoc />
+        protected override async Task WriteValueAsync(TMember[] value, Stream stream, GraphBinaryWriter writer)
+        {
+            await writer.WriteValueAsync(value.Length, stream, false).ConfigureAwait(false);
+            
+            foreach (var item in value)
+            {
+                await writer.WriteAsync(item, stream).ConfigureAwait(false);
+            }
+        }
+        
+        /// <summary>
+        /// Currently not supported as GraphBinary has no array data type.
+        /// </summary>
+        protected override Task<TMember[]> ReadValueAsync(Stream stream, GraphBinaryReader reader)
+        {
+            throw new NotImplementedException("Reading an array is not supported");
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/BigDecimalSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/BigDecimalSerializer.cs
new file mode 100644
index 0000000..3aebd85
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/BigDecimalSerializer.cs
@@ -0,0 +1,90 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System;
+using System.IO;
+using System.Numerics;
+using System.Threading.Tasks;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary.Types
+{
+    /// <summary>
+    /// A serializer that serializes <see cref="decimal"/> values as BigDecimal in GraphBinary.
+    /// </summary>
+    public class BigDecimalSerializer : SimpleTypeSerializer<decimal>
+    {
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="BigDecimalSerializer" /> class.
+        /// </summary>
+        public BigDecimalSerializer() : base(DataType.BigDecimal)
+        {
+        }
+
+        /// <inheritdoc />
+        protected override async Task WriteValueAsync(decimal value, Stream stream, GraphBinaryWriter writer)
+        {
+            var (unscaledValue, scale) = GetUnscaledValueAndScale(value);
+            await writer.WriteValueAsync(scale, stream, false).ConfigureAwait(false);
+            await writer.WriteValueAsync(unscaledValue, stream, false).ConfigureAwait(false);
+        }
+        
+        private static (BigInteger, int) GetUnscaledValueAndScale(decimal input)
+        {
+            var parts = decimal.GetBits(input);
+
+            var sign = (parts[3] & 0x80000000) != 0;
+            
+            var scale = (parts[3] >> 16) & 0x7F;
+
+            var lowBytes = BitConverter.GetBytes(parts[0]);
+            var middleBytes = BitConverter.GetBytes(parts[1]);
+            var highBytes = BitConverter.GetBytes(parts[2]);
+            var valueBytes = new byte[12];
+            lowBytes.CopyTo(valueBytes, 0);
+            middleBytes.CopyTo(valueBytes, 4);
+            highBytes.CopyTo(valueBytes, 8);
+            var bigInt = new BigInteger(valueBytes);
+
+            if (sign)
+            {
+                bigInt = -bigInt;
+            }
+            
+            return (bigInt, scale);
+        }
+
+        /// <inheritdoc />
+        protected override async Task<decimal> ReadValueAsync(Stream stream, GraphBinaryReader reader)
+        {
+            var scale = (int) await reader.ReadValueAsync<int>(stream, false).ConfigureAwait(false);
+            var unscaled = (BigInteger) await reader.ReadValueAsync<BigInteger>(stream, false).ConfigureAwait(false);
+
+            return ConvertScaleAndUnscaledValue(scale, unscaled);
+        }
+
+        private static decimal ConvertScaleAndUnscaledValue(int scale, BigInteger unscaledValue)
+        {
+            return (decimal) unscaledValue * (decimal) Math.Pow(10, -scale);
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/BigIntegerSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/BigIntegerSerializer.cs
new file mode 100644
index 0000000..e781504
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/BigIntegerSerializer.cs
@@ -0,0 +1,60 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System.IO;
+using System.Linq;
+using System.Numerics;
+using System.Threading.Tasks;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary.Types
+{
+    /// <summary>
+    /// A serializer for <see cref="BigInteger"/> values.
+    /// </summary>
+    public class BigIntegerSerializer : SimpleTypeSerializer<BigInteger>
+    {
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="BigIntegerSerializer" /> class.
+        /// </summary>
+        public BigIntegerSerializer() : base(DataType.BigInteger)
+        {
+        }
+
+        /// <inheritdoc />
+        protected override async Task WriteValueAsync(BigInteger value, Stream stream, GraphBinaryWriter writer)
+        {
+            var bytes = value.ToByteArray().Reverse().ToArray();
+            await writer.WriteValueAsync(bytes.Length, stream, false).ConfigureAwait(false);
+            await stream.WriteAsync(bytes).ConfigureAwait(false);
+        }
+
+        /// <inheritdoc />
+        protected override async Task<BigInteger> ReadValueAsync(Stream stream, GraphBinaryReader reader)
+        {
+            var length = (int) await reader.ReadValueAsync<int>(stream, false).ConfigureAwait(false);
+            var bytes = new byte[length];
+            await stream.ReadAsync(bytes).ConfigureAwait(false);
+            return new BigInteger(bytes.Reverse().ToArray());
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/BindingSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/BindingSerializer.cs
new file mode 100644
index 0000000..1cb5d9a
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/BindingSerializer.cs
@@ -0,0 +1,57 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System.IO;
+using System.Threading.Tasks;
+using Gremlin.Net.Process.Traversal;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary.Types
+{
+    /// <summary>
+    /// A serializer for <see cref="Binding"/> values.
+    /// </summary>
+    public class BindingSerializer : SimpleTypeSerializer<Binding>
+    {
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="BindingSerializer" /> class.
+        /// </summary>
+        public BindingSerializer() : base(DataType.Binding)
+        {
+        }
+
+        /// <inheritdoc />
+        protected override async Task WriteValueAsync(Binding value, Stream stream, GraphBinaryWriter writer)
+        {
+            await writer.WriteValueAsync(value.Key, stream, false).ConfigureAwait(false);
+            await writer.WriteAsync(value.Value, stream).ConfigureAwait(false);
+        }
+
+        /// <inheritdoc />
+        protected override async Task<Binding> ReadValueAsync(Stream stream, GraphBinaryReader reader)
+        {
+            var key = (string) await reader.ReadValueAsync<string>(stream, false).ConfigureAwait(false);
+            var value = await reader.ReadAsync(stream).ConfigureAwait(false);
+            return new Binding(key, value);
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/BulkSetSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/BulkSetSerializer.cs
new file mode 100644
index 0000000..862c2c7
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/BulkSetSerializer.cs
@@ -0,0 +1,72 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System.Collections;
+using System.IO;
+using System.Threading.Tasks;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary.Types
+{
+    /// <summary>
+    /// A serializer for the GraphBinary type BulkSet that gets converted to <typeparamref name="TList"/>.
+    /// </summary>
+    /// <typeparam name="TList">The type of the list to convert the BulkSet into.</typeparam>
+    public class BulkSetSerializer<TList> : SimpleTypeSerializer<TList>
+        where TList : IList, new()
+    {
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="BulkSetSerializer{TList}" /> class.
+        /// </summary>
+        public BulkSetSerializer() : base(DataType.BulkSet)
+        {
+        }
+
+        
+        /// <summary>
+        /// Currently not supported.
+        /// </summary>
+        protected override Task WriteValueAsync(TList value, Stream stream, GraphBinaryWriter writer)
+        {
+            throw new System.NotImplementedException("Writing a BulkSet is not supported");
+        }
+
+        /// <inheritdoc />
+        protected override async Task<TList> ReadValueAsync(Stream stream, GraphBinaryReader reader)
+        {
+            var length = (int) await reader.ReadValueAsync<int>(stream, false).ConfigureAwait(false);
+
+            var result = new TList();
+            for (var i = 0; i < length; i++)
+            {
+                var value = await reader.ReadAsync(stream).ConfigureAwait(false);
+                var bulk = (long) await reader.ReadValueAsync<long>(stream, false).ConfigureAwait(false);
+                for (var j = 0; j < bulk; j++)
+                {
+                    result.Add(value);
+                }
+            }
+
+            return result;
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ByteBufferSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ByteBufferSerializer.cs
new file mode 100644
index 0000000..0e3bf1d
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ByteBufferSerializer.cs
@@ -0,0 +1,58 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System.IO;
+using System.Threading.Tasks;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary.Types
+{
+    
+    /// <summary>
+    /// A serializer for byte[].
+    /// </summary>
+    public class ByteBufferSerializer : SimpleTypeSerializer<byte[]>
+    {
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="ByteBufferSerializer" /> class.
+        /// </summary>
+        public ByteBufferSerializer() : base(DataType.ByteBuffer)
+        {
+        }
+
+        /// <inheritdoc />
+        protected override async Task WriteValueAsync(byte[] value, Stream stream, GraphBinaryWriter writer)
+        {
+            await writer.WriteValueAsync(value.Length, stream, false).ConfigureAwait(false);
+            await stream.WriteAsync(value, 0, value.Length).ConfigureAwait(false);
+        }
+
+        /// <inheritdoc />
+        protected override async Task<byte[]> ReadValueAsync(Stream stream, GraphBinaryReader reader)
+        {
+            var length = (int) await reader.ReadValueAsync<int>(stream, false).ConfigureAwait(false);
+            var buffer = new byte[length];
+            await stream.ReadAsync(buffer, 0, length).ConfigureAwait(false);
+            return buffer;
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ByteCodeSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ByteCodeSerializer.cs
new file mode 100644
index 0000000..bc59b4b
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ByteCodeSerializer.cs
@@ -0,0 +1,105 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System.Collections.Generic;
+using System.IO;
+using System.Threading.Tasks;
+using Gremlin.Net.Process.Traversal;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary.Types
+{
+    /// <summary>
+    /// A <see cref="Bytecode"/> serializer.
+    /// </summary>
+    public class BytecodeSerializer : SimpleTypeSerializer<Bytecode>
+    {
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="BytecodeSerializer" /> class.
+        /// </summary>
+        public BytecodeSerializer() : base(DataType.Bytecode)
+        {
+        }
+
+        /// <inheritdoc />
+        protected override async Task WriteValueAsync(Bytecode value, Stream stream, GraphBinaryWriter writer)
+        {
+            await WriteInstructionsAsync(value.StepInstructions, stream, writer).ConfigureAwait(false);
+            await WriteInstructionsAsync(value.SourceInstructions, stream, writer).ConfigureAwait(false);
+        }
+
+        private static async Task WriteInstructionsAsync(IReadOnlyCollection<Instruction> instructions, Stream stream,
+            GraphBinaryWriter writer)
+        {
+            await writer.WriteValueAsync(instructions.Count, stream, false).ConfigureAwait(false);
+
+            foreach (var instruction in instructions)
+            {
+                await writer.WriteValueAsync(instruction.OperatorName, stream, false).ConfigureAwait(false);
+                await WriteArgumentsAsync(instruction.Arguments, stream, writer).ConfigureAwait(false);
+            }
+        }
+
+        private static async Task WriteArgumentsAsync(object[] arguments, Stream stream, GraphBinaryWriter writer)
+        {
+            await writer.WriteValueAsync(arguments.Length, stream, false).ConfigureAwait(false);
+
+            foreach (var value in arguments)
+            {
+                await writer.WriteAsync(value, stream).ConfigureAwait(false);
+            }
+        }
+
+        /// <inheritdoc />
+        protected override async Task<Bytecode> ReadValueAsync(Stream stream, GraphBinaryReader reader)
+        {
+            var result = new Bytecode();
+
+            var stepsLength = (int) await reader.ReadValueAsync<int>(stream, false).ConfigureAwait(false);
+            for (var i = 0; i < stepsLength; i++)
+            {
+                result.AddStep((string) await reader.ReadValueAsync<string>(stream, false).ConfigureAwait(false),
+                    await ReadArgumentsAsync(stream, reader).ConfigureAwait(false));
+            }
+            
+            var sourcesLength = await stream.ReadIntAsync().ConfigureAwait(false);
+            for (var i = 0; i < sourcesLength; i++)
+            {
+                result.AddSource((string) await reader.ReadValueAsync<string>(stream, false).ConfigureAwait(false),
+                    await ReadArgumentsAsync(stream, reader).ConfigureAwait(false));
+            }
+            
+            return result;
+        }
+
+        private static async Task<object[]> ReadArgumentsAsync(Stream stream, GraphBinaryReader reader)
+        {
+            var valuesLength = (int) await reader.ReadValueAsync<int>(stream, false).ConfigureAwait(false);
+            var values = new object[valuesLength];
+            for (var i = 0; i < valuesLength; i++)
+            {
+                values[i] = await reader.ReadAsync(stream).ConfigureAwait(false);
+            }
+            return values;
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/CharSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/CharSerializer.cs
new file mode 100644
index 0000000..3c456cd
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/CharSerializer.cs
@@ -0,0 +1,84 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System.IO;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary.Types
+{
+    /// <summary>
+    /// A <see cref="char"/> serializer.
+    /// </summary>
+    public class CharSerializer : SimpleTypeSerializer<char>
+    {
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="CharSerializer" /> class.
+        /// </summary>
+        public CharSerializer() : base(DataType.Char)
+        {
+        }
+
+        /// <inheritdoc />
+        protected override async Task WriteValueAsync(char value, Stream stream, GraphBinaryWriter writer)
+        {
+            var bytes = Encoding.UTF8.GetBytes(value.ToString());
+            await stream.WriteAsync(bytes).ConfigureAwait(false);
+        }
+
+        /// <inheritdoc />
+        protected override async Task<char> ReadValueAsync(Stream stream, GraphBinaryReader reader)
+        {
+            var firstByte = await stream.ReadByteAsync().ConfigureAwait(false);
+            var byteLength = 1;
+            // A byte with the first byte ON (10000000) signals that more bytes are needed to represent the UTF-8 char
+            if ((firstByte & 0x80) > 0)
+            {
+                if ((firstByte & 0xf0) == 0xf0)
+                { // 0xf0 = 11110000
+                    byteLength = 4;
+                } else if ((firstByte & 0xe0) == 0xe0)
+                { //11100000
+                    byteLength = 3;
+                } else if ((firstByte & 0xc0) == 0xc0)
+                { //11000000
+                    byteLength = 2;
+                }
+            }
+
+            byte[] bytes;
+            if (byteLength == 1)
+            {
+                bytes = new[] {firstByte};
+            }
+            else
+            {
+                bytes = new byte[byteLength];
+                bytes[0] = firstByte;
+                await stream.ReadAsync(bytes, 1, byteLength - 1).ConfigureAwait(false);
+            }
+
+            return Encoding.UTF8.GetChars(bytes)[0];
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ClassSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ClassSerializer.cs
new file mode 100644
index 0000000..721c7fe
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ClassSerializer.cs
@@ -0,0 +1,58 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System;
+using System.IO;
+using System.Threading.Tasks;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary.Types
+{
+    /// <summary>
+    /// A serializer for the GraphBinary type class that takes <see cref="GremlinType"/> objects as their .NET
+    /// representation. 
+    /// </summary>
+    public class ClassSerializer : SimpleTypeSerializer<GremlinType>
+    {
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="ClassSerializer" /> class.
+        /// </summary>
+        public ClassSerializer() : base(DataType.Class)
+        {
+        }
+
+        /// <inheritdoc />
+        protected override async Task WriteValueAsync(GremlinType value, Stream stream, GraphBinaryWriter writer)
+        {
+            await writer.WriteValueAsync(value.Fqcn, stream, false).ConfigureAwait(false);
+        }
+
+        
+        /// <summary>
+        /// Currently not supported.
+        /// </summary>
+        protected override Task<GremlinType> ReadValueAsync(Stream stream, GraphBinaryReader reader)
+        {
+            throw new NotImplementedException("Reading a Class is not supported");
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/DateTimeOffsetSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/DateTimeOffsetSerializer.cs
new file mode 100644
index 0000000..52ffae3
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/DateTimeOffsetSerializer.cs
@@ -0,0 +1,63 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System;
+using System.IO;
+using System.Threading.Tasks;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary.Types
+{
+    /// <summary>
+    /// A serializer for the GraphBinary types Date and Timestamp. Both are represented as <see cref="DateTimeOffset"/>
+    /// in .NET.
+    /// </summary>
+    public class DateTimeOffsetSerializer : SimpleTypeSerializer<DateTimeOffset>
+    {
+        /// <summary>
+        /// A serializer for the GraphBinary type Date, represented as <see cref="DateTimeOffset"/> in .NET.
+        /// </summary>
+        public static readonly DateTimeOffsetSerializer DateSerializer = new DateTimeOffsetSerializer(DataType.Date);
+
+        /// <summary>
+        /// A serializer for the GraphBinary type Timestamp, represented as <see cref="DateTimeOffset"/> in .NET.
+        /// </summary>
+        public static readonly DateTimeOffsetSerializer TimestampSerializer =
+            new DateTimeOffsetSerializer(DataType.Timestamp);
+        
+        private DateTimeOffsetSerializer(DataType dataType) : base(dataType)
+        {
+        }
+
+        /// <inheritdoc />
+        protected override async Task WriteValueAsync(DateTimeOffset value, Stream stream, GraphBinaryWriter writer)
+        {
+            await stream.WriteLongAsync(value.ToUnixTimeMilliseconds()).ConfigureAwait(false);
+        }
+
+        /// <inheritdoc />
+        protected override async Task<DateTimeOffset> ReadValueAsync(Stream stream, GraphBinaryReader reader)
+        {
+            return DateTimeOffset.FromUnixTimeMilliseconds(await stream.ReadLongAsync().ConfigureAwait(false));
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/DurationSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/DurationSerializer.cs
new file mode 100644
index 0000000..89e669d
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/DurationSerializer.cs
@@ -0,0 +1,58 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System;
+using System.IO;
+using System.Threading.Tasks;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary.Types
+{
+    /// <summary>
+    /// A serializer that serializes <see cref="TimeSpan"/> values as Duration in GraphBinary.
+    /// </summary>
+    public class DurationSerializer : SimpleTypeSerializer<TimeSpan>
+    {
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="DurationSerializer" /> class.
+        /// </summary>
+        public DurationSerializer() : base(DataType.Duration)
+        {
+        }
+
+        /// <inheritdoc />
+        protected override async Task WriteValueAsync(TimeSpan value, Stream stream, GraphBinaryWriter writer)
+        {
+            await stream.WriteLongAsync((long) value.TotalSeconds).ConfigureAwait(false);
+            await stream.WriteIntAsync(value.Milliseconds * 1_000_000).ConfigureAwait(false);
+        }
+
+        /// <inheritdoc />
+        protected override async Task<TimeSpan> ReadValueAsync(Stream stream, GraphBinaryReader reader)
+        {
+            var seconds = await stream.ReadLongAsync().ConfigureAwait(false);
+            var nanoseconds = await stream.ReadIntAsync().ConfigureAwait(false);
+
+            return TimeSpan.FromSeconds(seconds) + TimeSpan.FromMilliseconds(nanoseconds / 1_000_000);
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/EdgeSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/EdgeSerializer.cs
new file mode 100644
index 0000000..81e925c
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/EdgeSerializer.cs
@@ -0,0 +1,79 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System.IO;
+using System.Threading.Tasks;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary.Types
+{
+    /// <summary>
+    /// An <see cref="Edge"/> serializer.
+    /// </summary>
+    public class EdgeSerializer : SimpleTypeSerializer<Edge>
+    {
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="EdgeSerializer" /> class.
+        /// </summary>
+        public EdgeSerializer() : base(DataType.Edge)
+        {
+        }
+
+        /// <inheritdoc />
+        protected override async Task WriteValueAsync(Edge value, Stream stream, GraphBinaryWriter writer)
+        {
+            await writer.WriteAsync(value.Id, stream).ConfigureAwait(false);
+            await writer.WriteValueAsync(value.Label, stream, false).ConfigureAwait(false);
+            
+            await writer.WriteAsync(value.InV.Id, stream).ConfigureAwait(false);
+            await writer.WriteValueAsync(value.InV.Label, stream, false).ConfigureAwait(false);
+            await writer.WriteAsync(value.OutV.Id, stream).ConfigureAwait(false);
+            await writer.WriteValueAsync(value.OutV.Label, stream, false).ConfigureAwait(false);
+
+            // Placeholder for the parent vertex
+            await writer.WriteAsync(null, stream).ConfigureAwait(false);
+            
+            // placeholder for the properties
+            await writer.WriteAsync(null, stream).ConfigureAwait(false);
+        }
+
+        /// <inheritdoc />
+        protected override async Task<Edge> ReadValueAsync(Stream stream, GraphBinaryReader reader)
+        {
+            var id = await reader.ReadAsync(stream).ConfigureAwait(false);
+            var label = (string) await reader.ReadValueAsync<string>(stream, false).ConfigureAwait(false);
+
+            var inV = new Vertex(await reader.ReadAsync(stream).ConfigureAwait(false),
+                (string) await reader.ReadValueAsync<string>(stream, false).ConfigureAwait(false));
+            var outV = new Vertex(await reader.ReadAsync(stream).ConfigureAwait(false),
+                (string) await reader.ReadValueAsync<string>(stream, false).ConfigureAwait(false));
+            
+            // discard possible parent vertex
+            await reader.ReadAsync(stream).ConfigureAwait(false);
+
+            // discard possible properties
+            await reader.ReadAsync(stream).ConfigureAwait(false);
+
+            return new Edge(id, outV, label, inV);
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/EnumSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/EnumSerializer.cs
new file mode 100644
index 0000000..d561c2a
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/EnumSerializer.cs
@@ -0,0 +1,124 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using Gremlin.Net.Process.Traversal;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary.Types
+{
+    /// <summary>
+    /// Provides serializers for enum types.
+    /// </summary>
+    public static class EnumSerializers
+    {
+        /// <summary>
+        /// A serializer for <see cref="Barrier"/> values.
+        /// </summary>
+        public static readonly EnumSerializer<Barrier> BarrierSerializer =
+            new EnumSerializer<Barrier>(DataType.Barrier, Barrier.GetByValue);
+
+        /// <summary>
+        /// A serializer for <see cref="Cardinality"/> values.
+        /// </summary>
+        public static readonly EnumSerializer<Cardinality> CardinalitySerializer =
+            new EnumSerializer<Cardinality>(DataType.Cardinality, Cardinality.GetByValue);
+
+        /// <summary>
+        /// A serializer for <see cref="Column"/> values.
+        /// </summary>
+        public static readonly EnumSerializer<Column> ColumnSerializer =
+            new EnumSerializer<Column>(DataType.Column, Column.GetByValue);
+
+        /// <summary>
+        /// A serializer for <see cref="Direction"/> values.
+        /// </summary>
+        public static readonly EnumSerializer<Direction> DirectionSerializer =
+            new EnumSerializer<Direction>(DataType.Direction, Direction.GetByValue);
+
+        /// <summary>
+        /// A serializer for <see cref="Operator"/> values.
+        /// </summary>
+        public static readonly EnumSerializer<Operator> OperatorSerializer =
+            new EnumSerializer<Operator>(DataType.Operator, Operator.GetByValue);
+
+        /// <summary>
+        /// A serializer for <see cref="Order"/> values.
+        /// </summary>
+        public static readonly EnumSerializer<Order> OrderSerializer =
+            new EnumSerializer<Order>(DataType.Order, Order.GetByValue);
+
+        /// <summary>
+        /// A serializer for <see cref="Pick"/> values.
+        /// </summary>
+        public static readonly EnumSerializer<Pick> PickSerializer =
+            new EnumSerializer<Pick>(DataType.Pick, Pick.GetByValue);
+
+        /// <summary>
+        /// A serializer for <see cref="Pop"/> values.
+        /// </summary>
+        public static readonly EnumSerializer<Pop> PopSerializer =
+            new EnumSerializer<Pop>(DataType.Pop, Pop.GetByValue);
+
+        /// <summary>
+        /// A serializer for <see cref="Scope"/> values.
+        /// </summary>
+        public static readonly EnumSerializer<Scope> ScopeSerializer =
+            new EnumSerializer<Scope>(DataType.Scope, Scope.GetByValue);
+
+        /// <summary>
+        /// A serializer for <see cref="T"/> values.
+        /// </summary>
+        public static readonly EnumSerializer<T> TSerializer =
+            new EnumSerializer<T>(DataType.T, T.GetByValue);
+    }
+
+    /// <summary>
+    /// Generalized serializer for enum types.
+    /// </summary>
+    /// <typeparam name="TEnum">The type of the enum to serialize.</typeparam>
+    public class EnumSerializer<TEnum> : SimpleTypeSerializer<TEnum>
+        where TEnum : EnumWrapper
+    {
+        private readonly Func<string, TEnum> _readFunc;
+
+        internal EnumSerializer(DataType dataType, Func<string, TEnum> readFunc) : base(dataType)
+        {
+            _readFunc = readFunc;
+        }
+
+        /// <inheritdoc />
+        protected override async Task WriteValueAsync(TEnum value, Stream stream, GraphBinaryWriter writer)
+        {
+            await writer.WriteAsync(value.EnumValue, stream).ConfigureAwait(false);
+        }
+
+        /// <inheritdoc />
+        protected override async Task<TEnum> ReadValueAsync(Stream stream, GraphBinaryReader reader)
+        {
+            var enumValue = (string) await reader.ReadAsync(stream).ConfigureAwait(false);
+            return _readFunc.Invoke(enumValue);
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/GremlinType.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/GremlinType.cs
new file mode 100644
index 0000000..4484454
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/GremlinType.cs
@@ -0,0 +1,49 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+namespace Gremlin.Net.Structure.IO.GraphBinary.Types
+{
+    /// <summary>
+    ///     Represents the GraphBinary type Class which can be used to serialize a class.
+    /// </summary>
+    public class GremlinType
+    {
+        /// <summary>
+        /// Gets the fully qualified class name that identifies the class in Java.
+        /// </summary>
+        public string Fqcn { get; }
+
+        private GremlinType(string fqcn)
+        {
+            Fqcn = fqcn;
+        }
+
+        /// <summary>
+        /// Creates a GremlinType for this fully qualified class name (fqcn).
+        /// </summary>
+        public static GremlinType FromFqcn(string fqcn)
+        {
+            return new GremlinType(fqcn);
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/LambdaSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/LambdaSerializer.cs
new file mode 100644
index 0000000..b7f0683
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/LambdaSerializer.cs
@@ -0,0 +1,62 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System.IO;
+using System.Threading.Tasks;
+using Gremlin.Net.Process.Traversal;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary.Types
+{
+    /// <summary>
+    /// A serializer for lambdas.
+    /// </summary>
+    public class LambdaSerializer : SimpleTypeSerializer<ILambda>
+    {
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="LambdaSerializer" /> class.
+        /// </summary>
+        public LambdaSerializer() : base(DataType.Lambda)
+        {
+        }
+
+        /// <inheritdoc />
+        protected override async Task WriteValueAsync(ILambda value, Stream stream, GraphBinaryWriter writer)
+        {
+            await writer.WriteValueAsync(value.Language, stream, false).ConfigureAwait(false);
+            await writer.WriteValueAsync(value.LambdaExpression, stream, false).ConfigureAwait(false);
+            await writer.WriteValueAsync(value.Arguments, stream, false).ConfigureAwait(false);
+        }
+
+        /// <inheritdoc />
+        protected override async Task<ILambda> ReadValueAsync(Stream stream, GraphBinaryReader reader)
+        {
+            var language = (string) await reader.ReadValueAsync<string>(stream, false).ConfigureAwait(false);
+            var expression = (string) await reader.ReadValueAsync<string>(stream, false).ConfigureAwait(false);
+            
+            // discard the arguments
+            await reader.ReadValueAsync<int>(stream, false).ConfigureAwait(false);
+
+            return new StringBasedLambda(expression, language);
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ListSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ListSerializer.cs
new file mode 100644
index 0000000..ad374e9
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ListSerializer.cs
@@ -0,0 +1,67 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System.Collections.Generic;
+using System.IO;
+using System.Threading.Tasks;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary.Types
+{
+    /// <summary>
+    /// A generic list serializer.
+    /// </summary>
+    /// <typeparam name="TMember">The type of elements in the list.</typeparam>
+    public class ListSerializer<TMember> : SimpleTypeSerializer<IList<TMember>>
+    {
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="ListSerializer{TList}" /> class.
+        /// </summary>
+        public ListSerializer() : base(DataType.List)
+        {
+        }
+
+        /// <inheritdoc />
+        protected override async Task WriteValueAsync(IList<TMember> value, Stream stream, GraphBinaryWriter writer)
+        {
+            await writer.WriteValueAsync(value.Count, stream, false).ConfigureAwait(false);
+            
+            foreach (var item in value)
+            {
+                await writer.WriteAsync(item, stream).ConfigureAwait(false);
+            }
+        }
+
+        /// <inheritdoc />
+        protected override async Task<IList<TMember>> ReadValueAsync(Stream stream, GraphBinaryReader reader)
+        {
+            var length = (int) await reader.ReadValueAsync<int>(stream, false).ConfigureAwait(false);
+            var result = new List<TMember>(length);
+            for (var i = 0; i < length; i++)
+            {
+                result.Add((TMember) await reader.ReadAsync(stream).ConfigureAwait(false));
+            }
+
+            return result;
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/MapSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/MapSerializer.cs
new file mode 100644
index 0000000..60c7e4a
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/MapSerializer.cs
@@ -0,0 +1,72 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System.Collections.Generic;
+using System.IO;
+using System.Threading.Tasks;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary.Types
+{
+    /// <summary>
+    /// A generic dictionary serializer.
+    /// </summary>
+    /// <typeparam name="TKey">The type of keys in the dictionary.</typeparam>
+    /// <typeparam name="TValue">The type of values in the dictionary.</typeparam>
+    public class MapSerializer<TKey, TValue> : SimpleTypeSerializer<IDictionary<TKey, TValue>>
+    {
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="MapSerializer{TKey, TValue}" /> class.
+        /// </summary>
+        public MapSerializer() : base(DataType.Map)
+        {
+        }
+
+        /// <inheritdoc />
+        protected override async Task WriteValueAsync(IDictionary<TKey, TValue> value, Stream stream, GraphBinaryWriter writer)
+        {
+            await writer.WriteValueAsync(value.Count, stream, false).ConfigureAwait(false);
+
+            foreach (var key in value.Keys)
+            {
+                await writer.WriteAsync(key, stream).ConfigureAwait(false);
+                await writer.WriteAsync(value[key], stream).ConfigureAwait(false);
+            }
+        }
+
+        /// <inheritdoc />
+        protected override async Task<IDictionary<TKey, TValue>> ReadValueAsync(Stream stream, GraphBinaryReader reader)
+        {
+            var length = await stream.ReadIntAsync().ConfigureAwait(false);
+            var result = new Dictionary<TKey, TValue>(length);
+            
+            for (var i = 0; i < length; i++)
+            {
+                var key = (TKey) await reader.ReadAsync(stream).ConfigureAwait(false);
+                var value = (TValue) await reader.ReadAsync(stream).ConfigureAwait(false);
+                result.Add(key, value);
+            }
+
+            return result;
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/PSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/PSerializer.cs
new file mode 100644
index 0000000..194d3f7
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/PSerializer.cs
@@ -0,0 +1,99 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading.Tasks;
+using Gremlin.Net.Process.Traversal;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary.Types
+{
+    /// <summary>
+    /// A <see cref="P"/> serializer.
+    /// </summary>
+    public class PSerializer : SimpleTypeSerializer<P>
+    {
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="PSerializer" /> class.
+        /// </summary>
+        public PSerializer(DataType typeOfP) : base(typeOfP)
+        {
+        }
+
+        /// <inheritdoc />
+        protected override async Task WriteValueAsync(P value, Stream stream, GraphBinaryWriter writer)
+        {
+            ICollection args = value.Value is ICollection ? value.Value : new List<object> {value.Value};
+
+            var argsLength = value.Other == null ? args.Count : args.Count + 1;
+            
+            await writer.WriteValueAsync(value.OperatorName, stream, false).ConfigureAwait(false);
+            await writer.WriteValueAsync(argsLength, stream, false).ConfigureAwait(false);
+
+            foreach (var arg in args)
+            {
+                await writer.WriteAsync(arg, stream).ConfigureAwait(false);
+            }
+
+            if (value.Other != null)
+            {
+                await writer.WriteAsync(value.Other, stream).ConfigureAwait(false);
+            }
+        }
+
+        /// <inheritdoc />
+        protected override async Task<P> ReadValueAsync(Stream stream, GraphBinaryReader reader)
+        {
+            var operatorName = (string) await reader.ReadValueAsync<string>(stream, false).ConfigureAwait(false);
+            var argsLength = (int) await reader.ReadValueAsync<int>(stream, false).ConfigureAwait(false);
+
+            var args = new object[argsLength];
+            for (var i = 0; i < argsLength; i++)
+            {
+                args[i] = await reader.ReadAsync(stream).ConfigureAwait(false);
+            }
+
+            if (operatorName == "and" || operatorName == "or")
+            {
+                
+                return new P(operatorName, (P) args[0], (P) args[1]);
+            }
+
+            if (operatorName == "not")
+            {
+                return new P(operatorName, (P) args[0]);
+            }
+
+            if (argsLength == 1)
+            {
+                if (DataType == DataType.TextP)
+                {
+                    return new TextP(operatorName, (string) args[0]);
+                }
+                return new P(operatorName, args[0]);
+            }
+            return new P(operatorName, args);
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/PathSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/PathSerializer.cs
new file mode 100644
index 0000000..70e3891
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/PathSerializer.cs
@@ -0,0 +1,69 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System.Collections.Generic;
+using System.IO;
+using System.Threading.Tasks;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary.Types
+{
+    /// <summary>
+    /// A <see cref="Path"/> serializer.
+    /// </summary>
+    public class PathSerializer : SimpleTypeSerializer<Path>
+    {
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="PathSerializer" /> class.
+        /// </summary>
+        public PathSerializer() : base(DataType.Path)
+        {
+        }
+
+        /// <inheritdoc />
+        protected override async Task WriteValueAsync(Path value, Stream stream, GraphBinaryWriter writer)
+        {
+            await writer.WriteAsync(value.Labels, stream).ConfigureAwait(false);
+            await writer.WriteAsync(value.Objects, stream).ConfigureAwait(false);
+        }
+
+        /// <inheritdoc />
+        protected override async Task<Path> ReadValueAsync(Stream stream, GraphBinaryReader reader)
+        {
+            var readLabelObjects = (List<object>) await reader.ReadAsync(stream).ConfigureAwait(false);
+            var labels = new List<ISet<string>>();
+            foreach (var labelObjectList in readLabelObjects)
+            {
+                var labelSet = new HashSet<string>();
+                foreach (var labelObj in (HashSet<object>) labelObjectList)
+                {
+                    labelSet.Add((string) labelObj);
+                }
+                labels.Add(labelSet);
+            }
+            
+            var objects = (List<object>) await reader.ReadAsync(stream).ConfigureAwait(false);
+            
+            return new Path(labels, objects);
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/PropertySerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/PropertySerializer.cs
new file mode 100644
index 0000000..cb7f5ed
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/PropertySerializer.cs
@@ -0,0 +1,63 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System.IO;
+using System.Threading.Tasks;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary.Types
+{
+    /// <summary>
+    /// A <see cref="Property"/> serializer.
+    /// </summary>
+    public class PropertySerializer : SimpleTypeSerializer<Property>
+    {
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="PropertySerializer" /> class.
+        /// </summary>
+        public PropertySerializer() : base(DataType.Property)
+        {
+        }
+
+        /// <inheritdoc />
+        protected override async Task WriteValueAsync(Property value, Stream stream, GraphBinaryWriter writer)
+        {
+            await writer.WriteValueAsync(value.Key, stream, false).ConfigureAwait(false);
+            await writer.WriteAsync(value.Value, stream).ConfigureAwait(false);
+            
+            // placeholder for the parent element
+            await writer.WriteAsync(null, stream).ConfigureAwait(false);
+        }
+
+        /// <inheritdoc />
+        protected override async Task<Property> ReadValueAsync(Stream stream, GraphBinaryReader reader)
+        {
+            var p = new Property((string) await reader.ReadValueAsync<string>(stream, false).ConfigureAwait(false),
+                await reader.ReadAsync(stream).ConfigureAwait(false));
+
+            // discard parent element
+            await reader.ReadAsync(stream).ConfigureAwait(false);
+            
+            return p;
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/SetSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/SetSerializer.cs
new file mode 100644
index 0000000..ae4a366
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/SetSerializer.cs
@@ -0,0 +1,74 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary.Types
+{
+    /// <summary>
+    /// A generic set serializer.
+    /// </summary>
+    /// <typeparam name="TSet">The type of the set to serialize.</typeparam>
+    /// <typeparam name="TMember">The type of elements in the set.</typeparam>
+    public class SetSerializer<TSet, TMember> : SimpleTypeSerializer<TSet>
+        where TSet : ISet<TMember>, new()
+    {
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="SetSerializer{TSet,TMember}" /> class.
+        /// </summary>
+        public SetSerializer() : base(DataType.Set)
+        {
+        }
+
+        /// <inheritdoc />
+        protected override async Task WriteValueAsync(TSet value, Stream stream, GraphBinaryWriter writer)
+        {
+            var enumerable = (IEnumerable) value;
+            var list = enumerable.Cast<object>().ToList();
+
+            await writer.WriteValueAsync(list.Count, stream, false).ConfigureAwait(false);
+            
+            foreach (var item in list)
+            {
+                await writer.WriteAsync(item, stream).ConfigureAwait(false);
+            }
+        }
+
+        /// <inheritdoc />
+        protected override async Task<TSet> ReadValueAsync(Stream stream, GraphBinaryReader reader)
+        {
+            var length = (int) await reader.ReadValueAsync<int>(stream, false).ConfigureAwait(false);
+            var result = new TSet();
+            for (var i = 0; i < length; i++)
+            {
+                result.Add((TMember) await reader.ReadAsync(stream).ConfigureAwait(false));
+            }
+
+            return result;
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/SimpleTypeSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/SimpleTypeSerializer.cs
new file mode 100644
index 0000000..498566b
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/SimpleTypeSerializer.cs
@@ -0,0 +1,113 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System.IO;
+using System.Threading.Tasks;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary.Types
+{
+    /// <summary>
+    /// Base class for serialization of types that don't contain type specific information only {type_code},
+    /// {value_flag} and {value}.
+    /// </summary>
+    /// <typeparam name="T">The supported type.</typeparam>
+    public abstract class SimpleTypeSerializer<T> : ITypeSerializer
+    {
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="SimpleTypeSerializer{T}" /> class.
+        /// </summary>
+        protected SimpleTypeSerializer(DataType dataType)
+        {
+            DataType = dataType;
+        }
+
+        /// <inheritdoc />
+        public DataType DataType { get; }
+
+        /// <inheritdoc />
+        public async Task WriteAsync(object value, Stream stream, GraphBinaryWriter writer)
+        {
+            await WriteValueAsync((T) value, stream, writer, true).ConfigureAwait(false);
+        }
+
+        /// <inheritdoc />
+        public async Task WriteValueAsync(object value, Stream stream, GraphBinaryWriter writer, bool nullable)
+        {
+            if (value == null)
+            {
+                if (!nullable)
+                {
+                    throw new IOException("Unexpected null value when nullable is false");
+                }
+
+                await writer.WriteValueFlagNullAsync(stream).ConfigureAwait(false);
+                return;
+            }
+
+            if (nullable)
+            {
+                await writer.WriteValueFlagNoneAsync(stream).ConfigureAwait(false);
+            }
+
+            await WriteValueAsync((T) value, stream, writer).ConfigureAwait(false);
+        }
+
+        /// <summary>
+        /// Writes a non-nullable value into a stream.
+        /// </summary>
+        /// <param name="value">The value to write.</param>
+        /// <param name="stream">The stream to write to.</param>
+        /// <param name="writer">A <see cref="GraphBinaryWriter"/>.</param>
+        /// <returns>A task that represents the asynchronous write operation.</returns>
+        protected abstract Task WriteValueAsync(T value, Stream stream, GraphBinaryWriter writer);
+
+        /// <inheritdoc />
+        public async Task<object> ReadAsync(Stream stream, GraphBinaryReader reader)
+        {
+            return await ReadValueAsync(stream, reader, true).ConfigureAwait(false);
+        }
+
+        /// <inheritdoc />
+        public async Task<object> ReadValueAsync(Stream stream, GraphBinaryReader reader, bool nullable)
+        {
+            if (nullable)
+            {
+                var valueFlag = await stream.ReadByteAsync().ConfigureAwait(false);
+                if ((valueFlag & 1) == 1)
+                {
+                    return null;
+                }
+            }
+
+            return await ReadValueAsync(stream, reader).ConfigureAwait(false);
+        }
+
+        /// <summary>
+        /// Reads a non-nullable value according to the type format.
+        /// </summary>
+        /// <param name="stream">The GraphBinary data to parse.</param>
+        /// <param name="reader">A <see cref="GraphBinaryReader"/>.</param>
+        /// <returns>The read value.</returns>
+        protected abstract Task<T> ReadValueAsync(Stream stream, GraphBinaryReader reader);
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/SingleTypeSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/SingleTypeSerializer.cs
new file mode 100644
index 0000000..c2c9f58
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/SingleTypeSerializer.cs
@@ -0,0 +1,111 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System;
+using System.IO;
+using System.Threading.Tasks;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary.Types
+{
+    /// <summary>
+    /// Provides serializers for types that can be represented as a single value and that can be read and write in a
+    /// single operation.
+    /// </summary>
+    public static class SingleTypeSerializers
+    {
+        /// <summary>
+        /// A serializer for <see cref="int"/> values.
+        /// </summary>
+        public static readonly SingleTypeSerializer<int> IntSerializer = new SingleTypeSerializer<int>(DataType.Int,
+            (value, stream) => stream.WriteIntAsync(value), stream => stream.ReadIntAsync());
+        
+        /// <summary>
+        /// A serializer for <see cref="long"/> values.
+        /// </summary>
+        public static readonly SingleTypeSerializer<long> LongSerializer = new SingleTypeSerializer<long>(DataType.Long,
+            (value, stream) => stream.WriteLongAsync(value), stream => stream.ReadLongAsync());
+
+        /// <summary>
+        /// A serializer for <see cref="double"/> values.
+        /// </summary>
+        public static readonly SingleTypeSerializer<double> DoubleSerializer =
+            new SingleTypeSerializer<double>(DataType.Double, (value, stream) => stream.WriteDoubleAsync(value),
+                stream => stream.ReadDoubleAsync());
+
+        /// <summary>
+        /// A serializer for <see cref="float"/> values.
+        /// </summary>
+        public static readonly SingleTypeSerializer<float> FloatSerializer =
+            new SingleTypeSerializer<float>(DataType.Float, (value, stream) => stream.WriteFloatAsync(value),
+                stream => stream.ReadFloatAsync());
+
+        /// <summary>
+        /// A serializer for <see cref="short"/> values.
+        /// </summary>
+        public static readonly SingleTypeSerializer<short> ShortSerializer =
+            new SingleTypeSerializer<short>(DataType.Short, (value, stream) => stream.WriteShortAsync(value),
+                stream => stream.ReadShortAsync());
+
+        /// <summary>
+        /// A serializer for <see cref="bool"/> values.
+        /// </summary>
+        public static readonly SingleTypeSerializer<bool> BooleanSerializer =
+            new SingleTypeSerializer<bool>(DataType.Boolean, (value, stream) => stream.WriteBoolAsync(value),
+                stream => stream.ReadBoolAsync());
+
+        /// <summary>
+        /// A serializer for <see cref="byte"/> values.
+        /// </summary>
+        public static readonly SingleTypeSerializer<byte> ByteSerializer = new SingleTypeSerializer<byte>(DataType.Byte,
+            (value, stream) => stream.WriteByteAsync(value), stream => stream.ReadByteAsync());
+    }
+    
+    /// <summary>
+    /// Represents a serializer for types that can be represented as a single value and that can be read and write in a
+    /// single operation.
+    /// </summary>
+    public class SingleTypeSerializer<T> : SimpleTypeSerializer<T>
+    {
+        private readonly Func<T, Stream, Task> _writeFunc;
+        private readonly Func<Stream, Task<T>> _readFunc;
+
+        internal SingleTypeSerializer(DataType dataType, Func<T, Stream, Task> writeFunc, Func<Stream, Task<T>> readFunc)
+            : base(dataType)
+        {
+            _writeFunc = writeFunc;
+            _readFunc = readFunc;
+        }
+
+        /// <inheritdoc />
+        protected override async Task WriteValueAsync(T value, Stream stream, GraphBinaryWriter writer)
+        {
+            await _writeFunc.Invoke(value, stream).ConfigureAwait(false);
+        }
+
+        /// <inheritdoc />
+        protected override async Task<T> ReadValueAsync(Stream stream, GraphBinaryReader reader)
+        {
+            return await _readFunc.Invoke(stream).ConfigureAwait(false);
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/StringSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/StringSerializer.cs
new file mode 100644
index 0000000..c8d8dca
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/StringSerializer.cs
@@ -0,0 +1,59 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System.IO;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary.Types
+{
+    /// <summary>
+    /// A <see cref="string"/> serializer.
+    /// </summary>
+    public class StringSerializer : SimpleTypeSerializer<string>
+    {
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="StringSerializer" /> class.
+        /// </summary>
+        public StringSerializer() : base(DataType.String)
+        {
+        }
+
+        /// <inheritdoc />
+        protected override async Task WriteValueAsync(string value, Stream stream, GraphBinaryWriter writer)
+        {
+            var bytes = Encoding.UTF8.GetBytes(value);
+            await writer.WriteValueAsync(bytes.Length, stream, false).ConfigureAwait(false);
+            await stream.WriteAsync(bytes).ConfigureAwait(false);
+        }
+
+        /// <inheritdoc />
+        protected override async Task<string> ReadValueAsync(Stream stream, GraphBinaryReader reader)
+        {
+            var length = (int) await reader.ReadValueAsync<int>(stream, false).ConfigureAwait(false);
+            var bytes = new byte[length];
+            await stream.ReadAsync(bytes, 0, length).ConfigureAwait(false);
+            return Encoding.UTF8.GetString(bytes);
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/TraversalSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/TraversalSerializer.cs
new file mode 100644
index 0000000..d6fe159
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/TraversalSerializer.cs
@@ -0,0 +1,57 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using Gremlin.Net.Process.Traversal;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary.Types
+{
+    /// <summary>
+    /// A traversal serializer.
+    /// </summary>
+    public class TraversalSerializer : SimpleTypeSerializer<ITraversal>
+    {
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="TraversalSerializer" /> class.
+        /// </summary>
+        public TraversalSerializer() : base(DataType.Bytecode)
+        {
+        }
+
+        /// <inheritdoc />
+        protected override async Task WriteValueAsync(ITraversal value, Stream stream, GraphBinaryWriter writer)
+        {
+            await writer.WriteValueAsync(value.Bytecode, stream, false).ConfigureAwait(false);
+        }
+
+        /// <summary>
+        /// Currently not supported.
+        /// </summary>
+        protected override Task<ITraversal> ReadValueAsync(Stream stream, GraphBinaryReader reader)
+        {
+            throw new NotImplementedException("Reading a traversal is not supported");
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/TraversalStrategySerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/TraversalStrategySerializer.cs
new file mode 100644
index 0000000..af6e792
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/TraversalStrategySerializer.cs
@@ -0,0 +1,59 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using Gremlin.Net.Process.Traversal.Strategy;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary.Types
+{
+    /// <summary>
+    /// A traversal strategy serializer.
+    /// </summary>
+    public class TraversalStrategySerializer : SimpleTypeSerializer<AbstractTraversalStrategy>
+    {
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="TraversalStrategySerializer" /> class.
+        /// </summary>
+        public TraversalStrategySerializer() : base(DataType.TraversalStrategy)
+        {
+        }
+
+        /// <inheritdoc />
+        protected override async Task WriteValueAsync(AbstractTraversalStrategy value, Stream stream,
+            GraphBinaryWriter writer)
+        {
+            await writer.WriteValueAsync(GremlinType.FromFqcn(value.Fqcn), stream, false).ConfigureAwait(false);
+            await writer.WriteValueAsync(value.Configuration, stream, false).ConfigureAwait(false);
+        }
+
+        /// <summary>
+        /// Currently not supported.
+        /// </summary>
+        protected override Task<AbstractTraversalStrategy> ReadValueAsync(Stream stream, GraphBinaryReader reader)
+        {
+            throw new NotImplementedException("Reading a TraversalStrategy is not supported");
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/TraverserSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/TraverserSerializer.cs
new file mode 100644
index 0000000..8318813
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/TraverserSerializer.cs
@@ -0,0 +1,57 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System.IO;
+using System.Threading.Tasks;
+using Gremlin.Net.Process.Traversal;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary.Types
+{
+    /// <summary>
+    /// A <see cref="Traverser"/> serializer.
+    /// </summary>
+    public class TraverserSerializer : SimpleTypeSerializer<Traverser>
+    {
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="TraverserSerializer" /> class.
+        /// </summary>
+        public TraverserSerializer() : base(DataType.Traverser)
+        {
+        }
+
+        /// <inheritdoc />
+        protected override async Task WriteValueAsync(Traverser value, Stream stream, GraphBinaryWriter writer)
+        {
+            await writer.WriteValueAsync(value.Bulk, stream, false).ConfigureAwait(false);
+            await writer.WriteAsync(value.Object, stream).ConfigureAwait(false);
+        }
+
+        /// <inheritdoc />
+        protected override async Task<Traverser> ReadValueAsync(Stream stream, GraphBinaryReader reader)
+        {
+            var bulk = (long) await reader.ReadValueAsync<long>(stream, false).ConfigureAwait(false);
+            var v = await reader.ReadAsync(stream).ConfigureAwait(false);
+            return new Traverser(v, bulk);
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/TypeSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/TypeSerializer.cs
new file mode 100644
index 0000000..7723942
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/TypeSerializer.cs
@@ -0,0 +1,66 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using Gremlin.Net.Process.Traversal.Strategy;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary.Types
+{
+    /// <summary>
+    /// A serializer for .NET types represented as Class in GraphBinary. Currently only
+    /// <see cref="AbstractTraversalStrategy"/> types are supported.
+    /// </summary>
+    public class TypeSerializer : SimpleTypeSerializer<Type>
+    {
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="TypeSerializer" /> class.
+        /// </summary>
+        public TypeSerializer() : base(DataType.Class)
+        {
+        }
+
+        /// <inheritdoc />
+        protected override async Task WriteValueAsync(Type value, Stream stream, GraphBinaryWriter writer)
+        {
+            if (typeof(AbstractTraversalStrategy).IsAssignableFrom(value))
+            {
+                var strategyInstance = (AbstractTraversalStrategy) Activator.CreateInstance(value);
+                await writer.WriteValueAsync(strategyInstance.Fqcn, stream, false).ConfigureAwait(false);
+            }
+            else
+            {
+                throw new IOException("Currently, writing of Types is only supported for traversal strategies.");
+            }
+        }
+
+        /// <summary>
+        /// Currently not supported.
+        /// </summary>
+        protected override Task<Type> ReadValueAsync(Stream stream, GraphBinaryReader reader)
+        {
+            throw new NotImplementedException("Reading a Type is not supported");
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/UuidSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/UuidSerializer.cs
new file mode 100644
index 0000000..c65514a
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/UuidSerializer.cs
@@ -0,0 +1,108 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System;
+using System.IO;
+using System.Threading.Tasks;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary.Types
+{
+    /// <summary>
+    /// A serializer that serializes <see cref="Guid"/> values as Uuid in GraphBinary.
+    /// </summary>
+    public class UuidSerializer : SimpleTypeSerializer<Guid>
+    {
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="UuidSerializer" /> class.
+        /// </summary>
+        public UuidSerializer() : base(DataType.Uuid)
+        {
+        }
+
+        /// <inheritdoc />
+        protected override async Task WriteValueAsync(Guid value, Stream stream, GraphBinaryWriter writer)
+        {
+            var bytes = value.ToByteArray();
+            
+            // first 4 bytes in reverse order:
+            await stream.WriteByteAsync(bytes[3]).ConfigureAwait(false);
+            await stream.WriteByteAsync(bytes[2]).ConfigureAwait(false);
+            await stream.WriteByteAsync(bytes[1]).ConfigureAwait(false);
+            await stream.WriteByteAsync(bytes[0]).ConfigureAwait(false);
+            
+            // 2 bytes in reverse order:
+            await stream.WriteByteAsync(bytes[5]).ConfigureAwait(false);
+            await stream.WriteByteAsync(bytes[4]).ConfigureAwait(false);
+            
+            // 3 bytes in reverse order:
+            await stream.WriteByteAsync(bytes[7]).ConfigureAwait(false);
+            await stream.WriteByteAsync(bytes[6]).ConfigureAwait(false);
+            
+            // 3 bytes:
+            await stream.WriteByteAsync(bytes[8]).ConfigureAwait(false);
+            await stream.WriteByteAsync(bytes[9]).ConfigureAwait(false);
+            
+            // last 6 bytes:
+            await stream.WriteByteAsync(bytes[10]).ConfigureAwait(false);
+            await stream.WriteByteAsync(bytes[11]).ConfigureAwait(false);
+            await stream.WriteByteAsync(bytes[12]).ConfigureAwait(false);
+            await stream.WriteByteAsync(bytes[13]).ConfigureAwait(false);
+            await stream.WriteByteAsync(bytes[14]).ConfigureAwait(false);
+            await stream.WriteByteAsync(bytes[15]).ConfigureAwait(false);
+        }
+
+        /// <inheritdoc />
+        protected override async Task<Guid> ReadValueAsync(Stream stream, GraphBinaryReader reader)
+        {
+            var bytes = new byte[16];
+
+            // first 4 bytes in reverse order:
+            bytes[3] = await stream.ReadByteAsync().ConfigureAwait(false);
+            bytes[2] = await stream.ReadByteAsync().ConfigureAwait(false);
+            bytes[1] = await stream.ReadByteAsync().ConfigureAwait(false);
+            bytes[0] = await stream.ReadByteAsync().ConfigureAwait(false);
+            
+            // 2 bytes in reverse order:
+            bytes[5] = await stream.ReadByteAsync().ConfigureAwait(false);
+            bytes[4] = await stream.ReadByteAsync().ConfigureAwait(false);
+            
+            // 2 bytes in reverse order:
+            bytes[7] = await stream.ReadByteAsync().ConfigureAwait(false);
+            bytes[6] = await stream.ReadByteAsync().ConfigureAwait(false);
+            
+            // 2 bytes:
+            bytes[8] = await stream.ReadByteAsync().ConfigureAwait(false);
+            bytes[9] = await stream.ReadByteAsync().ConfigureAwait(false);
+            
+            // last 6 bytes:
+            bytes[10] = await stream.ReadByteAsync().ConfigureAwait(false);
+            bytes[11] = await stream.ReadByteAsync().ConfigureAwait(false);
+            bytes[12] = await stream.ReadByteAsync().ConfigureAwait(false);
+            bytes[13] = await stream.ReadByteAsync().ConfigureAwait(false);
+            bytes[14] = await stream.ReadByteAsync().ConfigureAwait(false);
+            bytes[15] = await stream.ReadByteAsync().ConfigureAwait(false);
+            
+            return new Guid(bytes);
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/VertexPropertySerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/VertexPropertySerializer.cs
new file mode 100644
index 0000000..f14cfd8
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/VertexPropertySerializer.cs
@@ -0,0 +1,72 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System.IO;
+using System.Threading.Tasks;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary.Types
+{
+    /// <summary>
+    /// A <see cref="VertexProperty"/> serializer.
+    /// </summary>
+    public class VertexPropertySerializer : SimpleTypeSerializer<VertexProperty>
+    {
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="VertexPropertySerializer" /> class.
+        /// </summary>
+        public VertexPropertySerializer() : base(DataType.VertexProperty)
+        {
+        }
+
+        /// <inheritdoc />
+        protected override async Task WriteValueAsync(VertexProperty value, Stream stream, GraphBinaryWriter writer)
+        {
+            await writer.WriteAsync(value.Id, stream).ConfigureAwait(false);
+            await writer.WriteValueAsync(value.Label, stream, false).ConfigureAwait(false);
+            await writer.WriteAsync(value.Value, stream).ConfigureAwait(false);
+            
+            // placeholder for the parent vertex
+            await writer.WriteAsync(null, stream).ConfigureAwait(false);
+            
+            // placeholder for properties
+            await writer.WriteAsync(null, stream).ConfigureAwait(false);
+
+        }
+
+        /// <inheritdoc />
+        protected override async Task<VertexProperty> ReadValueAsync(Stream stream, GraphBinaryReader reader)
+        {
+            var vp = new VertexProperty(await reader.ReadAsync(stream).ConfigureAwait(false),
+                (string) await reader.ReadValueAsync<string>(stream, false).ConfigureAwait(false),
+                await reader.ReadAsync(stream).ConfigureAwait(false));
+
+            // discard the parent vertex
+            await reader.ReadAsync(stream).ConfigureAwait(false);
+            
+            // discard the properties
+            await reader.ReadAsync(stream).ConfigureAwait(false);
+            
+            return vp;
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/VertexSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/VertexSerializer.cs
new file mode 100644
index 0000000..f4fc704
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/VertexSerializer.cs
@@ -0,0 +1,61 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System.IO;
+using System.Threading.Tasks;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary.Types
+{
+    /// <summary>
+    /// A <see cref="Vertex"/> serializer.
+    /// </summary>
+    public class VertexSerializer : SimpleTypeSerializer<Vertex>
+    {
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="VertexSerializer" /> class.
+        /// </summary>
+        public VertexSerializer() : base(DataType.Vertex)
+        {
+        }
+
+        /// <inheritdoc />
+        protected override async Task WriteValueAsync(Vertex value, Stream stream, GraphBinaryWriter writer)
+        {
+            await writer.WriteAsync(value.Id, stream).ConfigureAwait(false);
+            await writer.WriteValueAsync(value.Label, stream, false).ConfigureAwait(false);
+            await writer.WriteAsync(null, stream).ConfigureAwait(false);
+        }
+
+        /// <inheritdoc />
+        protected override async Task<Vertex> ReadValueAsync(Stream stream, GraphBinaryReader reader)
+        {
+
+            var v = new Vertex(await reader.ReadAsync(stream).ConfigureAwait(false),
+                (string) await reader.ReadValueAsync<string>(stream, false).ConfigureAwait(false));
+            
+            // discard properties
+            await reader.ReadAsync(stream).ConfigureAwait(false);
+            return v;
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/BigIntegerDeserializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/BigIntegerDeserializer.cs
index 755dbcc..a3f1ff6 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/BigIntegerDeserializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/BigIntegerDeserializer.cs
@@ -22,16 +22,15 @@
 #endregion
 
 using System.Numerics;
-using System.Xml;
-using Newtonsoft.Json.Linq;
+using System.Text.Json;
 
 namespace Gremlin.Net.Structure.IO.GraphSON
 {
     internal class BigIntegerDeserializer : IGraphSONDeserializer
     {
-        public dynamic Objectify(JToken graphsonObject, GraphSONReader reader)
+        public dynamic Objectify(JsonElement graphson, GraphSONReader reader)
         {
-            var bigInteger = graphsonObject.ToObject<string>();
+            var bigInteger = graphson.ValueKind == JsonValueKind.String ? graphson.GetString() : graphson.GetRawText();
             return BigInteger.Parse(bigInteger);
         }
     }
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/BulkSetSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/BulkSetSerializer.cs
index 58d4c9b..539224a 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/BulkSetSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/BulkSetSerializer.cs
@@ -23,17 +23,15 @@
 
 using System.Collections.Generic;
 using System.Linq;
-using System.Runtime.CompilerServices;
-using Newtonsoft.Json.Linq;
+using System.Text.Json;
 
 namespace Gremlin.Net.Structure.IO.GraphSON
 {
     internal class BulkSetSerializer : IGraphSONDeserializer
     {
-        public dynamic Objectify(JToken graphsonObject, GraphSONReader reader)
+        public dynamic Objectify(JsonElement graphsonObject, GraphSONReader reader)
         {
-            var jArray = graphsonObject as JArray;
-            if (jArray == null)
+            if (graphsonObject.ValueKind != JsonValueKind.Array)
             {
                 return new List<object>(0);
             }
@@ -42,9 +40,9 @@
             // so this query will be trouble. we'd need a legit BulkSet implementation here in C#. this current 
             // implementation is here to replicate the previous functionality that existed on the server side in 
             // previous versions.
-            return Enumerable.Range(0, jArray.Count / 2).SelectMany<int,object>(i =>
-                           Enumerable.Repeat<object>(reader.ToObject(jArray[i * 2]), (int) reader.ToObject(jArray[i * 2 + 1]))).
-                       ToList();
+            return Enumerable.Range(0, graphsonObject.GetArrayLength() / 2).SelectMany<int, object>(i =>
+                Enumerable.Repeat<object>(reader.ToObject(graphsonObject[i * 2]),
+                    (int) reader.ToObject(graphsonObject[i * 2 + 1]))).ToList();
         }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/ByteBufferDeserializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/ByteBufferDeserializer.cs
index f77abb0..0feb3a2 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/ByteBufferDeserializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/ByteBufferDeserializer.cs
@@ -21,15 +21,15 @@
 #endregion
 
 using System;
-using Newtonsoft.Json.Linq;
+using System.Text.Json;
 
 namespace Gremlin.Net.Structure.IO.GraphSON
 {
     internal class ByteBufferDeserializer : IGraphSONDeserializer
     {
-        public dynamic Objectify(JToken graphsonObject, GraphSONReader reader)
+        public dynamic Objectify(JsonElement graphsonObject, GraphSONReader reader)
         {
-            var base64String = graphsonObject.ToObject<string>();
+            var base64String = graphsonObject.GetString();
             return Convert.FromBase64String(base64String);
         }
     }
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/ByteConverter.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/ByteConverter.cs
index 6525d52..c9fc8a5 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/ByteConverter.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/ByteConverter.cs
@@ -20,14 +20,14 @@
  */
 #endregion
 
-using System;
+using System.Text.Json;
 
 namespace Gremlin.Net.Structure.IO.GraphSON
 {
-    internal class ByteConverter : NumberConverter
+    internal class ByteConverter : NumberConverter<byte>
     {
         protected override string GraphSONTypeName => "Byte";
-        protected override Type HandledType => typeof(byte);
         protected override string Prefix => "gx";
+        protected override dynamic FromJsonElement(JsonElement graphson) => graphson.GetByte();
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/CharConverter.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/CharConverter.cs
index b7023be..0c3e539 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/CharConverter.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/CharConverter.cs
@@ -20,15 +20,19 @@
  */
 #endregion
 
-using System;
+using System.Text.Json;
 
 namespace Gremlin.Net.Structure.IO.GraphSON
 {
-    internal class CharConverter : NumberConverter
+    internal class CharConverter : NumberConverter<char>
     {
         protected override string GraphSONTypeName => "Char";
-        protected override Type HandledType => typeof(char);
         protected override string Prefix => "gx";
         protected override bool StringifyValue => true;
+        protected override dynamic FromJsonElement(JsonElement graphson)
+        {
+            var deserializedByte = graphson.GetString();
+            return deserializedByte[0];
+        }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DateDeserializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DateDeserializer.cs
index 98ca25e..bc5bf61 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DateDeserializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DateDeserializer.cs
@@ -21,7 +21,7 @@
 #endregion
 
 using System;
-using Newtonsoft.Json.Linq;
+using System.Text.Json;
 
 namespace Gremlin.Net.Structure.IO.GraphSON
 {
@@ -29,9 +29,9 @@
     {
         private static readonly DateTimeOffset UnixStart = new DateTimeOffset(1970, 1, 1, 0, 0, 0, 0, TimeSpan.Zero);
 
-        public dynamic Objectify(JToken graphsonObject, GraphSONReader reader)
+        public dynamic Objectify(JsonElement graphsonObject, GraphSONReader reader)
         {
-            var milliseconds = graphsonObject.ToObject<long>();
+            var milliseconds = graphsonObject.GetInt64();
             return UnixStart.AddTicks(TimeSpan.TicksPerMillisecond * milliseconds);
         }
     }
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DateSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DateSerializer.cs
index d6c830a..a3c7263 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DateSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DateSerializer.cs
@@ -28,13 +28,10 @@
 {
     internal class DateSerializer : IGraphSONSerializer
     {
-        private static readonly DateTimeOffset UnixStart = new DateTimeOffset(1970, 1, 1, 0, 0, 0, 0, TimeSpan.Zero);
-        
         public Dictionary<string, dynamic> Dictify(dynamic objectData, GraphSONWriter writer)
         {
             DateTimeOffset value = objectData;
-            var ticks = (value - UnixStart).Ticks;
-            return GraphSONUtil.ToTypedValue("Date", ticks / TimeSpan.TicksPerMillisecond);
+            return GraphSONUtil.ToTypedValue("Date", value.ToUnixTimeMilliseconds());
         }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DecimalConverter.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DecimalConverter.cs
index 6860137..f195522 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DecimalConverter.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DecimalConverter.cs
@@ -21,15 +21,23 @@
 
 #endregion
 
-using System;
+using System.Globalization;
+using System.Text.Json;
 
 namespace Gremlin.Net.Structure.IO.GraphSON
 {
-    internal class DecimalConverter : NumberConverter
+    internal class DecimalConverter : NumberConverter<decimal>
     {
         protected override string GraphSONTypeName => "BigDecimal";
-        protected override Type HandledType => typeof(decimal);
         protected override string Prefix => "gx";
         protected override bool StringifyValue => true;
+        protected override dynamic FromJsonElement(JsonElement graphson)
+        {
+            if (graphson.ValueKind == JsonValueKind.String)
+            {
+                return decimal.Parse(graphson.GetString(), CultureInfo.InvariantCulture);
+            }
+            return graphson.GetDecimal();
+        }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DirectionDeserializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DirectionDeserializer.cs
index 4027171..34d4f61 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DirectionDeserializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DirectionDeserializer.cs
@@ -21,16 +21,16 @@
 
 #endregion
 
+using System.Text.Json;
 using Gremlin.Net.Process.Traversal;
-using Newtonsoft.Json.Linq;
 
 namespace Gremlin.Net.Structure.IO.GraphSON
 {
     internal class DirectionDeserializer : IGraphSONDeserializer
     {
-        public dynamic Objectify(JToken graphsonObject, GraphSONReader reader)
+        public dynamic Objectify(JsonElement graphsonObject, GraphSONReader reader)
         {
-            return Direction.GetByValue(graphsonObject.ToString());
+            return Direction.GetByValue(graphsonObject.GetString());
         }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DoubleConverter.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DoubleConverter.cs
index 416423b..ba5a2f7 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DoubleConverter.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DoubleConverter.cs
@@ -21,13 +21,52 @@
 
 #endregion
 
-using System;
+using System.Text.Json;
 
 namespace Gremlin.Net.Structure.IO.GraphSON
 {
-    internal class DoubleConverter : NumberConverter
+    internal class DoubleConverter : NumberConverter<double>
     {
         protected override string GraphSONTypeName => "Double";
-        protected override Type HandledType => typeof(double);
+        private const string NaN = "NaN";
+        private const string PositiveInfinity = "Infinity";
+        private const string NegativeInfinity = "-Infinity";
+
+        protected override dynamic FromJsonElement(JsonElement graphson)
+        {
+            if (graphson.ValueKind == JsonValueKind.String)
+            {
+                switch (graphson.GetString())
+                {
+                    case NaN:
+                        return double.NaN;
+                    case PositiveInfinity:
+                        return double.PositiveInfinity;
+                    case NegativeInfinity:
+                        return double.NegativeInfinity;
+                }
+            }  
+            return graphson.GetDouble();
+        }
+
+        protected override object ConvertInvalidNumber(double number)
+        {
+            if (double.IsNaN(number))
+            {
+                return NaN;
+            }
+
+            if (double.IsPositiveInfinity(number))
+            {
+                return PositiveInfinity;
+            }
+
+            if (double.IsNegativeInfinity(number))
+            {
+                return NegativeInfinity;
+            }
+            
+            return number;
+        }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DurationDeserializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DurationDeserializer.cs
index 00a9a70..2c1d17f 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DurationDeserializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DurationDeserializer.cs
@@ -21,16 +21,16 @@
 
 #endregion
 
+using System.Text.Json;
 using System.Xml;
-using Newtonsoft.Json.Linq;
 
 namespace Gremlin.Net.Structure.IO.GraphSON
 {
     internal class DurationDeserializer : IGraphSONDeserializer
     {
-        public dynamic Objectify(JToken graphsonObject, GraphSONReader reader)
+        public dynamic Objectify(JsonElement graphsonObject, GraphSONReader reader)
         {
-            var duration = graphsonObject.ToObject<string>();
+            var duration = graphsonObject.GetString();
             return XmlConvert.ToTimeSpan(duration);
         }
     }
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/EdgeDeserializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/EdgeDeserializer.cs
index 6ec8694..13f4ce0 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/EdgeDeserializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/EdgeDeserializer.cs
@@ -21,22 +21,28 @@
 
 #endregion
 
-using Newtonsoft.Json.Linq;
+using System.Text.Json;
 
 namespace Gremlin.Net.Structure.IO.GraphSON
 {
     internal class EdgeDeserializer : IGraphSONDeserializer
     {
-        public dynamic Objectify(JToken graphsonObject, GraphSONReader reader)
+        public dynamic Objectify(JsonElement graphsonObject, GraphSONReader reader)
         {
-            var outVId = reader.ToObject(graphsonObject["outV"]);
-            var outVLabel = (string) (graphsonObject["outVLabel"] ?? Vertex.DefaultLabel);
+            var outVId = reader.ToObject(graphsonObject.GetProperty("outV"));
+            var outVLabel = graphsonObject.TryGetProperty("outVLabel", out var outVLabelProperty)
+                ? outVLabelProperty.GetString()
+                : Vertex.DefaultLabel;
             var outV = new Vertex(outVId, outVLabel);
-            var inVId = reader.ToObject(graphsonObject["inV"]);
-            var inVLabel = (string) (graphsonObject["inVLabel"] ?? Vertex.DefaultLabel);
+            var inVId = reader.ToObject(graphsonObject.GetProperty("inV"));
+            var inVLabel = graphsonObject.TryGetProperty("inVLabel", out var inVLabelProperty)
+                ? inVLabelProperty.GetString()
+                : Vertex.DefaultLabel;
             var inV = new Vertex(inVId, inVLabel);
-            var edgeId = reader.ToObject(graphsonObject["id"]);
-            var edgeLabel = (string) graphsonObject["label"] ?? "edge";
+            var edgeId = reader.ToObject(graphsonObject.GetProperty("id"));
+            var edgeLabel = graphsonObject.TryGetProperty("label", out var labelProperty)
+                ? labelProperty.GetString()
+                : "edge";
             return new Edge(edgeId, outV, edgeLabel, inV);
         }
     }
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/FloatConverter.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/FloatConverter.cs
index 432aeab..5bbd9b2 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/FloatConverter.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/FloatConverter.cs
@@ -21,13 +21,13 @@
 
 #endregion
 
-using System;
+using System.Text.Json;
 
 namespace Gremlin.Net.Structure.IO.GraphSON
 {
-    internal class FloatConverter : NumberConverter
+    internal class FloatConverter : NumberConverter<float>
     {
         protected override string GraphSONTypeName => "Float";
-        protected override Type HandledType => typeof(float);
+        protected override dynamic FromJsonElement(JsonElement graphson) => graphson.GetSingle();
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSON2MessageSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSON2MessageSerializer.cs
new file mode 100644
index 0000000..c0c36b1
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSON2MessageSerializer.cs
@@ -0,0 +1,43 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+namespace Gremlin.Net.Structure.IO.GraphSON
+{
+    /// <summary>
+    ///     Serializes data to and from Gremlin Server in GraphSON2 format.
+    /// </summary>
+    public class GraphSON2MessageSerializer : GraphSONMessageSerializer
+    {
+        private const string MimeType = SerializationTokens.GraphSON2MimeType;
+
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="GraphSON2MessageSerializer" /> class with custom serializers.
+        /// </summary>
+        /// <param name="graphSONReader">The <see cref="GraphSON2Reader"/> used to deserialize from GraphSON.</param>
+        /// <param name="graphSONWriter">The <see cref="GraphSON2Writer"/> used to serialize to GraphSON.</param>
+        public GraphSON2MessageSerializer(GraphSON2Reader graphSONReader = null, GraphSON2Writer graphSONWriter = null)
+            : base(MimeType, graphSONReader ?? new GraphSON2Reader(), graphSONWriter ?? new GraphSON2Writer())
+        {
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSON3MessageSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSON3MessageSerializer.cs
new file mode 100644
index 0000000..abb6a75
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSON3MessageSerializer.cs
@@ -0,0 +1,43 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+namespace Gremlin.Net.Structure.IO.GraphSON
+{
+    /// <summary>
+    ///     Serializes data to and from Gremlin Server in GraphSON3 format.
+    /// </summary>
+    public class GraphSON3MessageSerializer : GraphSONMessageSerializer
+    {
+        private const string MimeType = SerializationTokens.GraphSON3MimeType;
+        
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="GraphSON3MessageSerializer" /> class with custom serializers.
+        /// </summary>
+        /// <param name="graphSONReader">The <see cref="GraphSON3Reader"/> used to deserialize from GraphSON.</param>
+        /// <param name="graphSONWriter">The <see cref="GraphSON3Writer"/> used to serialize to GraphSON.</param>
+        public GraphSON3MessageSerializer(GraphSON3Reader graphSONReader = null, GraphSON3Writer graphSONWriter = null)
+            : base(MimeType, graphSONReader ?? new GraphSON3Reader(), graphSONWriter ?? new GraphSON3Writer())
+        {
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONMessageSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONMessageSerializer.cs
new file mode 100644
index 0000000..817cdee
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONMessageSerializer.cs
@@ -0,0 +1,101 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Text.Json;
+using System.Threading.Tasks;
+using Gremlin.Net.Driver;
+using Gremlin.Net.Driver.Messages;
+
+namespace Gremlin.Net.Structure.IO.GraphSON
+{
+    /// <summary>
+    ///     Serializes data to and from Gremlin Server in GraphSON format.
+    /// </summary>
+    public abstract class GraphSONMessageSerializer : IMessageSerializer
+    {
+        private static readonly JsonSerializerOptions JsonDeserializingOptions = new JsonSerializerOptions
+            {PropertyNamingPolicy = JsonNamingPolicy.CamelCase};
+        private readonly string _mimeType;
+        private readonly GraphSONReader _graphSONReader;
+        private readonly GraphSONWriter _graphSONWriter;
+
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="GraphSONMessageSerializer" /> class.
+        /// </summary>
+        /// <param name="mimeType">The MIME type supported by this serializer.</param>
+        /// <param name="graphSONReader">The <see cref="GraphSONReader"/> used to deserialize from GraphSON.</param>
+        /// <param name="graphSonWriter">The <see cref="GraphSONWriter"/> used to serialize to GraphSON.</param>
+        protected GraphSONMessageSerializer(string mimeType, GraphSONReader graphSONReader,
+            GraphSONWriter graphSonWriter)
+        {
+            _mimeType = mimeType;
+            _graphSONReader = graphSONReader;
+            _graphSONWriter = graphSonWriter;
+        }
+
+        /// <inheritdoc />
+        public virtual Task<byte[]> SerializeMessageAsync(RequestMessage requestMessage)
+        {
+            var graphSONMessage = _graphSONWriter.WriteObject(requestMessage);
+            return Task.FromResult(Encoding.UTF8.GetBytes(MessageWithHeader(graphSONMessage)));
+        }
+
+        private string MessageWithHeader(string messageContent)
+        {
+            return $"{(char) _mimeType.Length}{_mimeType}{messageContent}";
+        }
+
+        /// <inheritdoc />
+        public virtual Task<ResponseMessage<List<object>>> DeserializeMessageAsync(byte[] message)
+        {
+            if (message == null) throw new ArgumentNullException(nameof(message));
+            if (message.Length == 0) return Task.FromResult<ResponseMessage<List<object>>>(null);
+            
+            var reader = new Utf8JsonReader(message);
+            var responseMessage =
+                JsonSerializer.Deserialize<ResponseMessage<JsonElement>>(ref reader, JsonDeserializingOptions);
+            if (responseMessage == null) return Task.FromResult<ResponseMessage<List<object>>>(null);;
+            
+            var data = _graphSONReader.ToObject(responseMessage.Result.Data);
+            return Task.FromResult(CopyMessageWithNewData(responseMessage, data));
+        }
+
+        private static ResponseMessage<List<object>> CopyMessageWithNewData(ResponseMessage<JsonElement> origMsg,
+            dynamic data)
+        {
+            return new ResponseMessage<List<object>>
+            {
+                RequestId = origMsg.RequestId,
+                Status = origMsg.Status,
+                Result = new ResponseResult<List<object>>
+                {
+                    Data = data == null ? null : new List<object>(data),
+                    Meta = origMsg.Result.Meta
+                }
+            };
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONReader.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONReader.cs
index 63641f0..16901bd 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONReader.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONReader.cs
@@ -24,7 +24,7 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
-using Newtonsoft.Json.Linq;
+using System.Text.Json;
 
 namespace Gremlin.Net.Structure.IO.GraphSON
 {
@@ -90,7 +90,7 @@
         /// </summary>
         /// <param name="graphSonData">The GraphSON collection to deserialize.</param>
         /// <returns>The deserialized object.</returns>
-        public virtual dynamic ToObject(IEnumerable<JToken> graphSonData)
+        public virtual dynamic ToObject(IEnumerable<JsonElement> graphSonData)
         {
             return graphSonData.Select(graphson => ToObject(graphson));
         }
@@ -98,52 +98,50 @@
         /// <summary>
         ///     Deserializes GraphSON to an object.
         /// </summary>
-        /// <param name="jToken">The GraphSON to deserialize.</param>
+        /// <param name="graphSon">The GraphSON to deserialize.</param>
         /// <returns>The deserialized object.</returns>
-        public virtual dynamic ToObject(JToken jToken)
+        public virtual dynamic ToObject(JsonElement graphSon)
         {
-            if (jToken is JArray)
+            switch (graphSon.ValueKind)
             {
-                return jToken.Select(t => ToObject(t));
+                case JsonValueKind.Array:
+                    return graphSon.EnumerateArray().Select(t => ToObject(t));
+                case JsonValueKind.String:
+                    return graphSon.GetString();
+                case JsonValueKind.Null:
+                    return null;
+                case JsonValueKind.True:
+                    return true;
+                case JsonValueKind.False:
+                    return false;
+                case JsonValueKind.Object:
+                    break;
+                default:
+                    throw new ArgumentOutOfRangeException(nameof(graphSon.ValueKind), graphSon.ValueKind,
+                        $"JSON type not supported.");
             }
-            if (jToken is JValue jValue)
+
+            if (graphSon.TryGetProperty(GraphSONTokens.TypeKey, out var graphSonTypeProperty))
             {
-                return jValue.Value;
+                return ReadValueOfType(graphSon, graphSonTypeProperty.GetString());
             }
-            if (!HasTypeKey(jToken))
-            {
-                return ReadDictionary(jToken);
-            }
-            return ReadTypedValue(jToken);
+            return ReadDictionary(graphSon);
+            
         }
 
-        private bool HasTypeKey(JToken jToken)
+        private dynamic ReadValueOfType(JsonElement typedValue, string graphSONType)
         {
-            var graphSONType = (string) jToken[GraphSONTokens.TypeKey];
-            return graphSONType != null;
-        }
-
-        private dynamic ReadTypedValue(JToken typedValue)
-        {
-            var graphSONType = (string) typedValue[GraphSONTokens.TypeKey];
             if (!Deserializers.TryGetValue(graphSONType, out var deserializer))
             {
                 throw new InvalidOperationException($"Deserializer for \"{graphSONType}\" not found");
             }
-            return deserializer.Objectify(typedValue[GraphSONTokens.ValueKey], this);
+            return deserializer.Objectify(typedValue.GetProperty(GraphSONTokens.ValueKey), this);
         }
-
-        private dynamic ReadDictionary(JToken jtokenDict)
+        
+        private dynamic ReadDictionary(JsonElement jsonDict)
         {
-            var dict = new Dictionary<string, dynamic>();
-            foreach (var e in jtokenDict)
-            {
-                var property = e as JProperty;
-                if (property == null)
-                    throw new InvalidOperationException($"Cannot read graphson: {jtokenDict}");
-                dict.Add(property.Name, ToObject(property.Value));
-            }
-            return dict;
+            return jsonDict.EnumerateObject()
+                .ToDictionary(property => property.Name, property => ToObject(property.Value));
         }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONWriter.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONWriter.cs
index dba6e60..dd4fa27 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONWriter.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONWriter.cs
@@ -26,11 +26,11 @@
 using System.Collections.Generic;
 using System.Linq;
 using System.Numerics;
-using System.Reflection;
+using System.Text.Encodings.Web;
+using System.Text.Json;
 using Gremlin.Net.Driver.Messages;
 using Gremlin.Net.Process.Traversal;
 using Gremlin.Net.Process.Traversal.Strategy;
-using Newtonsoft.Json;
 
 namespace Gremlin.Net.Structure.IO.GraphSON
 {
@@ -39,6 +39,9 @@
     /// </summary>
     public abstract class GraphSONWriter
     {
+        private static readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions
+            {Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping};
+        
         /// <summary>
         /// Contains the information of serializers by type.
         /// </summary>
@@ -103,7 +106,7 @@
         /// <returns>The serialized GraphSON.</returns>
         public virtual string WriteObject(dynamic objectData)
         {
-            return JsonConvert.SerializeObject(ToDict(objectData));
+            return JsonSerializer.Serialize(ToDict(objectData), _jsonOptions);
         }
 
         /// <summary>
@@ -113,17 +116,20 @@
         /// <returns>A GraphSON representation of the object ready to be serialized.</returns>
         public dynamic ToDict(dynamic objectData)
         {
-            var type = objectData.GetType();
+            if (objectData != null)
+            {
+                var type = objectData.GetType();
 
-            IGraphSONSerializer serializer = TryGetSerializerFor(type);
+                IGraphSONSerializer serializer = TryGetSerializerFor(type);
 
-            if (serializer != null)
-                return serializer.Dictify(objectData, this);
-            if (IsDictionaryType(type))
-                return DictToGraphSONDict(objectData);
-            if (IsCollectionType(type))
-                return CollectionToGraphSONCollection(objectData);
-            return objectData;
+                if (serializer != null)
+                    return serializer.Dictify(objectData, this);
+                if (IsDictionaryType(type))
+                    return DictToGraphSONDict(objectData);
+                if (IsCollectionType(type))
+                    return CollectionToGraphSONCollection(objectData);
+            }
+            return objectData;         
         }
 
         private IGraphSONSerializer TryGetSerializerFor(Type type)
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/IGraphSONDeserializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/IGraphSONDeserializer.cs
index b15b169..e0c4993 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/IGraphSONDeserializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/IGraphSONDeserializer.cs
@@ -21,7 +21,7 @@
 
 #endregion
 
-using Newtonsoft.Json.Linq;
+using System.Text.Json;
 
 namespace Gremlin.Net.Structure.IO.GraphSON
 {
@@ -36,6 +36,6 @@
         /// <param name="graphsonObject">The GraphSON object to objectify.</param>
         /// <param name="reader">A <see cref="GraphSONReader" /> that can be used to objectify properties of the GraphSON object.</param>
         /// <returns>The deserialized object.</returns>
-        dynamic Objectify(JToken graphsonObject, GraphSONReader reader);
+        dynamic Objectify(JsonElement graphsonObject, GraphSONReader reader);
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/Int16Converter.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/Int16Converter.cs
index abe5a77..6182de9 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/Int16Converter.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/Int16Converter.cs
@@ -21,14 +21,15 @@
 
 #endregion
 
-using System;
+using System.Text.Json;
 
 namespace Gremlin.Net.Structure.IO.GraphSON
 {
-    internal class Int16Converter : NumberConverter
+    internal class Int16Converter : NumberConverter<short>
     {
         protected override string GraphSONTypeName => "Int16";
-        protected override Type HandledType => typeof(short);
         protected override string Prefix => "gx";
+        
+        protected override dynamic FromJsonElement(JsonElement graphson) => graphson.GetInt16();
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/Int32Converter.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/Int32Converter.cs
index 052f938..6cdcdfd 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/Int32Converter.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/Int32Converter.cs
@@ -21,13 +21,14 @@
 
 #endregion
 
-using System;
+using System.Text.Json;
 
 namespace Gremlin.Net.Structure.IO.GraphSON
 {
-    internal class Int32Converter : NumberConverter
+    internal class Int32Converter : NumberConverter<int>
     {
         protected override string GraphSONTypeName => "Int32";
-        protected override Type HandledType => typeof(int);
+
+        protected override dynamic FromJsonElement(JsonElement graphson) => graphson.GetInt32();
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/Int64Converter.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/Int64Converter.cs
index dd0160f..c0192a8 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/Int64Converter.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/Int64Converter.cs
@@ -21,13 +21,14 @@
 
 #endregion
 
-using System;
+using System.Text.Json;
 
 namespace Gremlin.Net.Structure.IO.GraphSON
 {
-    internal class Int64Converter : NumberConverter
+    internal class Int64Converter : NumberConverter<long>
     {
         protected override string GraphSONTypeName => "Int64";
-        protected override Type HandledType => typeof(long);
+        
+        protected override dynamic FromJsonElement(JsonElement graphson) => graphson.GetInt64();
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/ListSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/ListSerializer.cs
index f432c7e..add8eb5 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/ListSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/ListSerializer.cs
@@ -21,12 +21,8 @@
 
 #endregion
 
-using System;
-using System.Collections;
 using System.Collections.Generic;
-using System.Linq;
-using Microsoft.Win32.SafeHandles;
-using Newtonsoft.Json.Linq;
+using System.Text.Json;
 
 namespace Gremlin.Net.Structure.IO.GraphSON
 {
@@ -34,17 +30,16 @@
     {
         private static readonly IReadOnlyList<object> EmptyList = new object[0];
         
-        public dynamic Objectify(JToken graphsonObject, GraphSONReader reader)
+        public dynamic Objectify(JsonElement graphsonObject, GraphSONReader reader)
         {
-            var jArray = graphsonObject as JArray;
-            if (jArray == null)
+            if (graphsonObject.ValueKind != JsonValueKind.Array)
             {
                 return EmptyList;
             }
-            var result = new object[jArray.Count];
+            var result = new object[graphsonObject.GetArrayLength()];
             for (var i = 0; i < result.Length; i++)
             {
-                result[i] = reader.ToObject(jArray[i]);
+                result[i] = reader.ToObject(graphsonObject[i]);
             }
             // object[] implements IList<object>
             return result;
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/MapSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/MapSerializer.cs
index a096e3e..99165a7 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/MapSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/MapSerializer.cs
@@ -24,23 +24,22 @@
 using System;
 using System.Collections;
 using System.Collections.Generic;
-using Newtonsoft.Json.Linq;
+using System.Text.Json;
 
 namespace Gremlin.Net.Structure.IO.GraphSON
 {
     internal class MapSerializer : IGraphSONDeserializer, IGraphSONSerializer
     {
-        public dynamic Objectify(JToken graphsonObject, GraphSONReader reader)
+        public dynamic Objectify(JsonElement graphsonObject, GraphSONReader reader)
         {
-            var jArray = graphsonObject as JArray;
-            if (jArray == null)
+            if (graphsonObject.ValueKind != JsonValueKind.Array)
             {
                 return new Dictionary<object, object>(0);
             }
-            var result = new Dictionary<object, object>(jArray.Count / 2);
-            for (var i = 0; i < jArray.Count; i += 2)
+            var result = new Dictionary<object, object>(graphsonObject.GetArrayLength() / 2);
+            for (var i = 0; i < graphsonObject.GetArrayLength(); i += 2)
             {
-                result[reader.ToObject(jArray[i])] = reader.ToObject(jArray[i + 1]);
+                result[reader.ToObject(graphsonObject[i])] = reader.ToObject(graphsonObject[i + 1]);
             }
             // IDictionary<object, object>
             return result;
@@ -48,8 +47,7 @@
         
         public Dictionary<string, dynamic> Dictify(dynamic objectData, GraphSONWriter writer)
         {
-            var map = objectData as IDictionary;
-            if (map == null)
+            if (!(objectData is IDictionary map))
             {
                 throw new InvalidOperationException("Object must implement IDictionary");
             }
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/NumberConverter.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/NumberConverter.cs
index 8127415..4492685 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/NumberConverter.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/NumberConverter.cs
@@ -21,33 +21,36 @@
 
 #endregion
 
-using System;
 using System.Collections.Generic;
 using System.Globalization;
-using Newtonsoft.Json.Linq;
+using System.Text.Json;
 
 namespace Gremlin.Net.Structure.IO.GraphSON
 {
-    internal abstract class NumberConverter : IGraphSONDeserializer, IGraphSONSerializer
+    internal abstract class NumberConverter<T> : IGraphSONDeserializer, IGraphSONSerializer
     {
         protected abstract string GraphSONTypeName { get; }
-        protected abstract Type HandledType { get; }
         protected virtual string Prefix => "g";
         protected virtual bool StringifyValue => false;
 
-        public dynamic Objectify(JToken graphsonObject, GraphSONReader reader)
+        public dynamic Objectify(JsonElement graphsonObject, GraphSONReader reader)
         {
-            return graphsonObject.ToObject(HandledType);
+            return FromJsonElement(graphsonObject);
         }
 
+        protected abstract dynamic FromJsonElement(JsonElement graphson);
+
         public Dictionary<string, dynamic> Dictify(dynamic objectData, GraphSONWriter writer)
         {
-            object value = objectData;
+            T number = objectData;
+            var value = ConvertInvalidNumber(number);
             if (StringifyValue)
             {
                 value = string.Format(CultureInfo.InvariantCulture, "{0}", value);
             }
             return GraphSONUtil.ToTypedValue(GraphSONTypeName, value, Prefix);
         }
+
+        protected virtual object ConvertInvalidNumber(T number) => number;
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/Path3Deserializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/Path3Deserializer.cs
index 4754135..d05663b 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/Path3Deserializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/Path3Deserializer.cs
@@ -23,21 +23,21 @@
 
 using System.Collections.Generic;
 using System.Linq;
-using Newtonsoft.Json.Linq;
+using System.Text.Json;
 
 namespace Gremlin.Net.Structure.IO.GraphSON
 {
     internal class Path3Deserializer : IGraphSONDeserializer
     {
-        public dynamic Objectify(JToken graphsonObject, GraphSONReader reader)
+        public dynamic Objectify(JsonElement graphsonObject, GraphSONReader reader)
         {
             // "labels" is a object[] where each item is ISet<object>
-            var labelProperty = (object[])reader.ToObject(graphsonObject["labels"]);
+            var labelProperty = (object[])reader.ToObject(graphsonObject.GetProperty("labels"));
             var labels = labelProperty
                 .Select(x => new HashSet<string>(((ISet<object>)x).Cast<string>()))
                 .ToList<ISet<string>>();
             // "objects" is an object[]
-            object[] objects = reader.ToObject(graphsonObject["objects"]);
+            object[] objects = reader.ToObject(graphsonObject.GetProperty("objects"));
             return new Path(labels, objects);
         }
     }
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/PathDeserializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/PathDeserializer.cs
index b322df8..3a37f66 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/PathDeserializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/PathDeserializer.cs
@@ -23,19 +23,21 @@
 
 using System.Collections.Generic;
 using System.Linq;
-using Newtonsoft.Json.Linq;
+using System.Text.Json;
 
 namespace Gremlin.Net.Structure.IO.GraphSON
 {
     internal class PathDeserializer : IGraphSONDeserializer
     {
-        public dynamic Objectify(JToken graphsonObject, GraphSONReader reader)
+        public dynamic Objectify(JsonElement graphsonObject, GraphSONReader reader)
         {
             var labels =
-                graphsonObject["labels"]
-                    .Select(readObjLabels => new HashSet<string>(readObjLabels.Select(l => (string) l)))
+                graphsonObject.GetProperty("labels").EnumerateArray()
+                    .Select(readObjLabels =>
+                        new HashSet<string>(readObjLabels.EnumerateArray().Select(l => l.GetString())))
                     .ToList<ISet<string>>();
-            var objects = graphsonObject["objects"].Select(o => reader.ToObject(o)).ToList();
+            var objects = graphsonObject.GetProperty("objects").EnumerateArray().Select(o => reader.ToObject(o))
+                .ToList();
             return new Path(labels, objects);
         }
     }
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/PropertyDeserializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/PropertyDeserializer.cs
index 11f160e..7c9ea0c 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/PropertyDeserializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/PropertyDeserializer.cs
@@ -21,17 +21,19 @@
 
 #endregion
 
-using Newtonsoft.Json.Linq;
+using System.Text.Json;
 
 namespace Gremlin.Net.Structure.IO.GraphSON
 {
     internal class PropertyDeserializer : IGraphSONDeserializer
     {
-        public dynamic Objectify(JToken graphsonObject, GraphSONReader reader)
+        public dynamic Objectify(JsonElement graphsonObject, GraphSONReader reader)
         {
-            var key = (string) graphsonObject["key"];
-            var value = reader.ToObject(graphsonObject["value"]);
-            var element = graphsonObject["element"] != null ? reader.ToObject(graphsonObject["element"]) : null;
+            var key = graphsonObject.GetProperty("key").GetString();
+            var value = reader.ToObject(graphsonObject.GetProperty("value"));
+            var element = graphsonObject.TryGetProperty("element", out var elementProperty)
+                ? reader.ToObject(elementProperty)
+                : null;
             return new Property(key, value, element);
         }
     }
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/SetSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/SetSerializer.cs
index e657bd8..590392e 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/SetSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/SetSerializer.cs
@@ -21,24 +21,22 @@
 
 #endregion
 
-using System;
 using System.Collections.Generic;
 using System.Linq;
-using Newtonsoft.Json.Linq;
+using System.Text.Json;
 
 namespace Gremlin.Net.Structure.IO.GraphSON
 {
     internal class SetSerializer : IGraphSONDeserializer, IGraphSONSerializer
     {
-        public dynamic Objectify(JToken graphsonObject, GraphSONReader reader)
+        public dynamic Objectify(JsonElement graphsonObject, GraphSONReader reader)
         {
-            var jArray = graphsonObject as JArray;
-            if (jArray == null)
+            if (graphsonObject.ValueKind != JsonValueKind.Array)
             {
                 return new HashSet<object>();
             }
             // ISet<object>
-            return new HashSet<object>(jArray.Select(reader.ToObject));
+            return new HashSet<object>(graphsonObject.EnumerateArray().Select(reader.ToObject));
         }
 
         public Dictionary<string, dynamic> Dictify(dynamic objectData, GraphSONWriter writer)
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/TDeserializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/TDeserializer.cs
index a3d972f..efbc542 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/TDeserializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/TDeserializer.cs
@@ -21,16 +21,16 @@
 
 #endregion
 
+using System.Text.Json;
 using Gremlin.Net.Process.Traversal;
-using Newtonsoft.Json.Linq;
 
 namespace Gremlin.Net.Structure.IO.GraphSON
 {
     internal class TDeserializer : IGraphSONDeserializer
     {
-        public dynamic Objectify(JToken graphsonObject, GraphSONReader reader)
+        public dynamic Objectify(JsonElement graphsonObject, GraphSONReader reader)
         {
-            return T.GetByValue(graphsonObject.ToString());
+            return T.GetByValue(graphsonObject.GetString());
         }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/TraverserReader.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/TraverserReader.cs
index abbb45f..1997325 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/TraverserReader.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/TraverserReader.cs
@@ -21,17 +21,17 @@
 
 #endregion
 
+using System.Text.Json;
 using Gremlin.Net.Process.Traversal;
-using Newtonsoft.Json.Linq;
 
 namespace Gremlin.Net.Structure.IO.GraphSON
 {
     internal class TraverserReader : IGraphSONDeserializer
     {
-        public dynamic Objectify(JToken graphsonObject, GraphSONReader reader)
+        public dynamic Objectify(JsonElement graphsonObject, GraphSONReader reader)
         {
-            var bulkObj = reader.ToObject(graphsonObject["bulk"]);
-            var valueObj = reader.ToObject(graphsonObject["value"]);
+            var bulkObj = reader.ToObject(graphsonObject.GetProperty("bulk"));
+            var valueObj = reader.ToObject(graphsonObject.GetProperty("value"));
             return new Traverser(valueObj, bulkObj);
         }
     }
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/UuidDeserializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/UuidDeserializer.cs
index 82ca43d..58caac7 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/UuidDeserializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/UuidDeserializer.cs
@@ -22,15 +22,17 @@
 #endregion
 
 using System;
-using Newtonsoft.Json.Linq;
+using System.Text.Json;
 
 namespace Gremlin.Net.Structure.IO.GraphSON
 {
     internal class UuidDeserializer : IGraphSONDeserializer
     {
-        public dynamic Objectify(JToken graphsonObject, GraphSONReader reader)
+        public dynamic Objectify(JsonElement graphsonObject, GraphSONReader reader)
         {
-            return graphsonObject.ToObject<Guid>();
+            var uuidString = graphsonObject.GetString();
+
+            return Guid.Parse(uuidString);
         }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/VertexDeserializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/VertexDeserializer.cs
index f1d64ed..72615ef 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/VertexDeserializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/VertexDeserializer.cs
@@ -21,16 +21,18 @@
 
 #endregion
 
-using Newtonsoft.Json.Linq;
+using System.Text.Json;
 
 namespace Gremlin.Net.Structure.IO.GraphSON
 {
     internal class VertexDeserializer : IGraphSONDeserializer
     {
-        public dynamic Objectify(JToken graphsonObject, GraphSONReader reader)
+        public dynamic Objectify(JsonElement graphsonObject, GraphSONReader reader)
         {
-            var id = reader.ToObject(graphsonObject["id"]);
-            var label = (string) graphsonObject["label"] ?? Vertex.DefaultLabel;
+            var id = reader.ToObject(graphsonObject.GetProperty("id"));
+            var label = graphsonObject.TryGetProperty("label", out var labelProperty)
+                ? labelProperty.GetString()
+                : Vertex.DefaultLabel;
             return new Vertex(id, label);
         }
     }
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/VertexPropertyDeserializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/VertexPropertyDeserializer.cs
index 7c2505f..15a99dc 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/VertexPropertyDeserializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/VertexPropertyDeserializer.cs
@@ -21,19 +21,19 @@
 
 #endregion
 
-using Newtonsoft.Json.Linq;
+using System.Text.Json;
 
 namespace Gremlin.Net.Structure.IO.GraphSON
 {
     internal class VertexPropertyDeserializer : IGraphSONDeserializer
     {
-        public dynamic Objectify(JToken graphsonObject, GraphSONReader reader)
+        public dynamic Objectify(JsonElement graphsonObject, GraphSONReader reader)
         {
-            var id = reader.ToObject(graphsonObject["id"]);
-            var label = (string) graphsonObject["label"];
-            var value = reader.ToObject(graphsonObject["value"]);
-            var vertex = graphsonObject["vertex"] != null
-                ? new Vertex(reader.ToObject(graphsonObject["vertex"]))
+            var id = reader.ToObject(graphsonObject.GetProperty("id"));
+            var label = graphsonObject.GetProperty("label").GetString();
+            var value = reader.ToObject(graphsonObject.GetProperty("value"));
+            var vertex = graphsonObject.TryGetProperty("vertex", out var vertexProperty)
+                ? new Vertex(reader.ToObject(vertexProperty))
                 : null;
             return new VertexProperty(id, label, value, vertex);
         }
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/SerializationTokens.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/SerializationTokens.cs
new file mode 100644
index 0000000..c615c7c
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/SerializationTokens.cs
@@ -0,0 +1,46 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+namespace Gremlin.Net.Structure.IO
+{
+    /// <summary>
+    ///     String constants used for serialization.
+    /// </summary>
+    public class SerializationTokens
+    {
+        /// <summary>
+        ///     The MIME type for GraphSON 2.
+        /// </summary>
+        public const string GraphSON2MimeType = "application/vnd.gremlin-v2.0+json";
+        
+        /// <summary>
+        ///     The MIME type for GraphSON 3.
+        /// </summary>
+        public const string GraphSON3MimeType = "application/vnd.gremlin-v3.0+json";
+
+        /// <summary>
+        ///     The MIME type for GraphBinary 1.
+        /// </summary>
+        public const string GraphBinary1MimeType = "application/vnd.graphbinary-v1.0";
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/Property.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/Property.cs
index daa052a..b2adee7 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/Property.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/Property.cs
@@ -35,8 +35,8 @@
         /// </summary>
         /// <param name="key">The key of the property.</param>
         /// <param name="value">The value of the property.</param>
-        /// <param name="element">The element that the property is associated with.</param>
-        public Property(string key, dynamic value, Element element)
+        /// <param name="element">The (optional) element that the property is associated with.</param>
+        public Property(string key, dynamic value, Element element = null)
         {
             Key = key;
             Value = value;
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/VertexProperty.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/VertexProperty.cs
index 8e20723..a8dd943 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/VertexProperty.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/VertexProperty.cs
@@ -34,8 +34,8 @@
         /// <param name="id">The id of the vertex property.</param>
         /// <param name="label">The label of the vertex property.</param>
         /// <param name="value">The id of the vertex property.</param>
-        /// <param name="vertex">The <see cref="Vertex" /> that owns this <see cref="VertexProperty" />.</param>
-        public VertexProperty(object id, string label, dynamic value, Vertex vertex)
+        /// <param name="vertex">The (optional) <see cref="Vertex" /> that owns this <see cref="VertexProperty" />.</param>
+        public VertexProperty(object id, string label, dynamic value, Vertex vertex = null)
             : base(id, label)
         {
             Value = value;
diff --git a/gremlin-dotnet/src/pom.xml b/gremlin-dotnet/src/pom.xml
index 2becde4..2c89923 100644
--- a/gremlin-dotnet/src/pom.xml
+++ b/gremlin-dotnet/src/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.apache.tinkerpop</groupId>
         <artifactId>gremlin-dotnet</artifactId>
-        <version>3.4.12-SNAPSHOT</version>
+        <version>3.5.1-SNAPSHOT</version>
     </parent>
     <artifactId>gremlin-dotnet-source</artifactId>
     <name>Apache TinkerPop :: Gremlin.Net - Source</name>
@@ -33,14 +33,40 @@
 
     <build>
         <plugins>
-            <!-- Override the execution from gremlin-dotnet to disable code generation from happening a second time -->
             <plugin>
                 <groupId>org.codehaus.gmavenplus</groupId>
                 <artifactId>gmavenplus-plugin</artifactId>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.codehaus.groovy</groupId>
+                        <artifactId>groovy-all</artifactId>
+                        <version>${groovy.version}</version>
+                        <type>pom</type>
+                        <scope>runtime</scope>
+                    </dependency>
+                </dependencies>
                 <executions>
                     <execution>
-                        <id>generate-dsl</id>
-                        <phase/>
+                        <id>update-version</id>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>execute</goal>
+                        </goals>
+                        <configuration>
+                            <scripts>
+                                <script>
+def mavenVersion = "${project.version}"
+def file = new File("${project.basedir}/Gremlin.Net/Gremlin.Net.csproj")
+file.write(file.getText("UTF-8").replaceFirst(/&lt;Version&gt;(.*)&lt;\/Version&gt;/, "&lt;Version&gt;" + mavenVersion + "&lt;/Version&gt;"))
+
+file = new File("${project.basedir}/Gremlin.Net.Template/Gremlin.Net.Template.csproj")
+file.write(file.getText("UTF-8").replaceFirst(/Version="(.*)"/, "Version=\"" + mavenVersion + "\""))
+
+file = new File("${project.basedir}/Gremlin.Net.Template/Gremlin.Net.Template.nuspec")
+file.write(file.getText("UTF-8").replaceFirst(/&lt;version&gt;(.*)&lt;\/version&gt;/, "&lt;version&gt;" + mavenVersion + "&lt;/version&gt;"))
+                                </script>
+                            </scripts>
+                        </configuration>
                     </execution>
                 </executions>
             </plugin>
@@ -301,18 +327,10 @@
                                 <configuration>
                                     <scripts>
                                         <script><![CDATA[
-// revert back the version after a SNAPSHOT deployment
+// prevent SNAPSHOT deployment for .NET
 def versionToUse = '${project.version}'
-def engine = new groovy.text.GStringTemplateEngine()
-def csprojTemplate = engine.createTemplate(new File('${project.parent.basedir}/glv/Gremlin.Net.csproj.template')).make(["projectVersion":versionToUse])
-def csprojFile = new File('${project.basedir}/Gremlin.Net/Gremlin.Net.csproj')
-csprojFile.newWriter().withWriter{ it << csprojTemplate }
-def templateCsprojTemplate = engine.createTemplate(new File('${project.parent.basedir}/glv/Gremlin.Net.Template.csproj.template')).make(["projectVersion":versionToUse])
-def templateCsprojFile = new File('${project.basedir}/Gremlin.Net.Template/Gremlin.Net.Template.csproj')
-templateCsprojFile.newWriter().withWriter{ it << templateCsprojTemplate }
-def nuspecTemplate = engine.createTemplate(new File('${project.parent.basedir}/glv/Gremlin.Net.Template.nuspec.template')).make(["projectVersion":versionToUse])
-def nuspecFile = new File('${project.basedir}/Gremlin.Net.Template/Gremlin.Net.Template.nuspec')
-nuspecFile.newWriter().withWriter{ it << nuspecTemplate }
+if (versionToUse.endsWith("-SNAPSHOT"))
+  throw new RuntimeException("Current version is a SNAPSHOT which can not be deployed to nuget")
 ]]>
                                         </script>
                                     </scripts>
diff --git a/gremlin-dotnet/test/Gremlin.Net.Benchmarks/Gremlin.Net.Benchmarks.csproj b/gremlin-dotnet/test/Gremlin.Net.Benchmarks/Gremlin.Net.Benchmarks.csproj
new file mode 100644
index 0000000..53f21d0
--- /dev/null
+++ b/gremlin-dotnet/test/Gremlin.Net.Benchmarks/Gremlin.Net.Benchmarks.csproj
@@ -0,0 +1,16 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+    <PropertyGroup>
+        <OutputType>Exe</OutputType>
+        <TargetFramework>netcoreapp3.1</TargetFramework>
+    </PropertyGroup>
+
+    <ItemGroup>
+      <PackageReference Include="BenchmarkDotNet" Version="0.12.1" />
+    </ItemGroup>
+
+    <ItemGroup>
+      <ProjectReference Include="..\..\src\Gremlin.Net\Gremlin.Net.csproj" />
+    </ItemGroup>
+
+</Project>
diff --git a/gremlin-dotnet/test/Gremlin.Net.Benchmarks/MessageSerializerBenchmarks.cs b/gremlin-dotnet/test/Gremlin.Net.Benchmarks/MessageSerializerBenchmarks.cs
new file mode 100644
index 0000000..500929a
--- /dev/null
+++ b/gremlin-dotnet/test/Gremlin.Net.Benchmarks/MessageSerializerBenchmarks.cs
@@ -0,0 +1,108 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using BenchmarkDotNet.Attributes;
+using Gremlin.Net.Driver;
+using Gremlin.Net.Driver.Messages;
+using Gremlin.Net.Process.Traversal;
+using Gremlin.Net.Structure.IO.GraphBinary;
+using Gremlin.Net.Structure.IO.GraphSON;
+using static Gremlin.Net.Process.Traversal.AnonymousTraversalSource;
+using static Gremlin.Net.Process.Traversal.__;
+using static Gremlin.Net.Process.Traversal.P;
+
+namespace Gremlin.Net.Benchmarks
+{
+    [MemoryDiagnoser]
+    public class MessageSerializerBenchmarks
+    {
+        private static readonly Bytecode EmptyBytecode = new Bytecode();
+
+        private static readonly Bytecode SomeBytecode = Traversal().WithComputer().V().
+            Has("Name", "marko").
+            Where(
+                Out("knows").
+                Has("name", Within(new List<string> {"stephen", "peter", "josh"})).
+                Count().
+                Is(Gt(3))).
+            Has("birthDate", Lt(DateTimeOffset.Parse("1980-01-01 00:00:00"))).
+            Bytecode;
+
+        private static readonly RequestMessage RequestMessageWithEmptyBytecode = RequestMessageFor(EmptyBytecode);
+        
+        private static readonly RequestMessage RequestMessage = RequestMessageFor(SomeBytecode);
+        
+        private static RequestMessage RequestMessageFor(Bytecode bytecode) => RequestMessage.Build(Tokens.OpsBytecode)
+            .Processor(Tokens.ProcessorTraversal).OverrideRequestId(Guid.NewGuid())
+            .AddArgument(Tokens.ArgsGremlin, bytecode).Create();
+
+        private static readonly GraphBinaryMessageSerializer BinaryMessageSerializer =
+            new GraphBinaryMessageSerializer();
+
+        private static readonly GraphSON3MessageSerializer
+            GraphSON3MessageSerializer = new GraphSON3MessageSerializer();
+        
+        [Benchmark]
+        public async Task<byte[]> TestWriteEmptyBytecodeBinary() =>
+            await BinaryMessageSerializer.SerializeMessageAsync(RequestMessageWithEmptyBytecode)
+                .ConfigureAwait(false);
+        
+        [Benchmark]
+        public async Task<byte[]> TestWriteEmptyBytecodeGraphSON3() =>
+            await GraphSON3MessageSerializer.SerializeMessageAsync(RequestMessageWithEmptyBytecode)
+                .ConfigureAwait(false);
+        
+        [Benchmark]
+        public async Task<byte[]> TestWriteBytecodeBinary() =>
+            await BinaryMessageSerializer.SerializeMessageAsync(RequestMessage)
+                .ConfigureAwait(false);
+        
+        [Benchmark]
+        public async Task<byte[]> TestWriteBytecodeGraphSON3() =>
+            await GraphSON3MessageSerializer.SerializeMessageAsync(RequestMessage)
+                .ConfigureAwait(false);
+
+        [Benchmark]
+        public async Task<ResponseMessage<List<object>>> TestReadSmallResponseMessageBinary() =>
+            await BinaryMessageSerializer.DeserializeMessageAsync(TestMessages.SmallBinaryResponseMessageBytes)
+                .ConfigureAwait(false);
+        
+        [Benchmark]
+        public async Task<ResponseMessage<List<object>>> TestReadSmallResponseMessageGraphSON3() =>
+            await GraphSON3MessageSerializer.DeserializeMessageAsync(TestMessages.SmallGraphSON3ResponseMessageBytes)
+                .ConfigureAwait(false);
+        
+        [Benchmark]
+        public async Task<ResponseMessage<List<object>>> TestReadBigResponseMessageBinary() =>
+            await BinaryMessageSerializer.DeserializeMessageAsync(TestMessages.BigBinaryResponseMessageBytes)
+                .ConfigureAwait(false);
+        
+        [Benchmark]
+        public async Task<ResponseMessage<List<object>>> TestReadBigResponseMessageGraphSON3() =>
+            await GraphSON3MessageSerializer.DeserializeMessageAsync(TestMessages.BigGraphSON3ResponseMessageBytes)
+                .ConfigureAwait(false);
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.Benchmarks/Program.cs b/gremlin-dotnet/test/Gremlin.Net.Benchmarks/Program.cs
new file mode 100644
index 0000000..070d4d6
--- /dev/null
+++ b/gremlin-dotnet/test/Gremlin.Net.Benchmarks/Program.cs
@@ -0,0 +1,35 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using BenchmarkDotNet.Running;
+
+namespace Gremlin.Net.Benchmarks
+{
+    public static class Program
+    {
+        public static void Main()
+        {
+            BenchmarkRunner.Run<MessageSerializerBenchmarks>();
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.Benchmarks/TestMessages.cs b/gremlin-dotnet/test/Gremlin.Net.Benchmarks/TestMessages.cs
new file mode 100644
index 0000000..68a1d2d
--- /dev/null
+++ b/gremlin-dotnet/test/Gremlin.Net.Benchmarks/TestMessages.cs
@@ -0,0 +1,2018 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+namespace Gremlin.Net.Benchmarks
+{
+    public class TestMessages
+    {
+        // small response message was created with the following traversal:
+        //   g.V().Count().Next();
+        public static readonly byte[] SmallBinaryResponseMessageBytes =
+        {
+            0x81, 0x00, 0x95, 0xDB, 0xE9, 0x49, 0xB4, 0x45, 0x48, 0x6B, 0xAF, 0xE1, 0xF0, 0xE0, 0xDB, 0x8E, 0x3F, 0xC1,
+            0x00, 0x00, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00,
+            0x04, 0x68, 0x6F, 0x73, 0x74, 0x03, 0x00, 0x00, 0x00, 0x00, 0x11, 0x2F, 0x31, 0x37, 0x32, 0x2E, 0x31, 0x37,
+            0x2E, 0x30, 0x2E, 0x31, 0x3A, 0x34, 0x31, 0x36, 0x35, 0x38, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+            0x00, 0x01, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x06
+        };
+        
+        // big response message was created with the following traversal:
+        //   g.V().
+        //      Repeat(__.Both()).Times(3).
+        //      Project<object>("vertex", "edgeCount", "knowsAndCreated", "path").
+        //      By(__.ElementMap<object>()).
+        //      By(__.BothE().Count()).
+        //      By(__.Coalesce<string>(
+        //          __.Out("knows", "created").Values<string>("name"),
+        //          __.Constant("nobody")).Fold()).
+        //      By(__.Path()).
+        //      ToList();
+        //
+        public static readonly byte[] BigBinaryResponseMessageBytes =
+        {
+            0x81, 0x00, 0xF1, 0x7B, 0x6E, 0x68, 0xDD, 0x54, 0x45, 0x64, 0x84, 0x26, 0x86, 0xCD, 0xAD, 0x57, 0xF6, 0x47,
+            0x00, 0x00, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00,
+            0x04, 0x68, 0x6F, 0x73, 0x74, 0x03, 0x00, 0x00, 0x00, 0x00, 0x11, 0x2F, 0x31, 0x37, 0x32, 0x2E, 0x31, 0x37,
+            0x2E, 0x30, 0x2E, 0x31, 0x3A, 0x34, 0x31, 0x34, 0x39, 0x30, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+            0x00, 0x1E, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04,
+            0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04,
+            0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x69, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x00,
+            0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x70,
+            0x65, 0x72, 0x73, 0x6F, 0x6E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6E, 0x61, 0x6D, 0x65, 0x03, 0x00, 0x00,
+            0x00, 0x00, 0x05, 0x6D, 0x61, 0x72, 0x6B, 0x6F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x01,
+            0x00, 0x00, 0x00, 0x00, 0x1D, 0x03, 0x00, 0x00, 0x00, 0x00, 0x09, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75,
+            0x6E, 0x74, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0F,
+            0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x09, 0x00, 0x00,
+            0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x76, 0x61, 0x64, 0x61, 0x73, 0x03, 0x00, 0x00, 0x00,
+            0x00, 0x04, 0x6A, 0x6F, 0x73, 0x68, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x6C, 0x6F, 0x70, 0x03, 0x00, 0x00,
+            0x00, 0x00, 0x04, 0x70, 0x61, 0x74, 0x68, 0x0E, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0B, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+            0x00, 0x00, 0x03, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72,
+            0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x73,
+            0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+            0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x01, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x76, 0x65, 0x72,
+            0x74, 0x65, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x69,
+            0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x6C, 0x61, 0x62,
+            0x65, 0x6C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x03, 0x00, 0x00, 0x00,
+            0x00, 0x04, 0x6E, 0x61, 0x6D, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6A, 0x6F, 0x73, 0x68, 0x03, 0x00,
+            0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00,
+            0x09, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72,
+            0x65, 0x61, 0x74, 0x65, 0x64, 0x09, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x72,
+            0x69, 0x70, 0x70, 0x6C, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x6C, 0x6F, 0x70, 0x03, 0x00, 0x00, 0x00,
+            0x00, 0x04, 0x70, 0x61, 0x74, 0x68, 0x0E, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0B, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+            0x00, 0x03, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73,
+            0x6F, 0x6E, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x73, 0x6F,
+            0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+            0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x01, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x76, 0x65, 0x72, 0x74,
+            0x65, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x69, 0x64,
+            0x01, 0x00, 0x00, 0x00, 0x00, 0x06, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x6C, 0x61, 0x62, 0x65,
+            0x6C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x03, 0x00, 0x00, 0x00, 0x00,
+            0x04, 0x6E, 0x61, 0x6D, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x70, 0x65, 0x74, 0x65, 0x72, 0x03, 0x00,
+            0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x01, 0x00, 0x00, 0x00, 0x00, 0x23, 0x03, 0x00, 0x00, 0x00, 0x00,
+            0x09, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72,
+            0x65, 0x61, 0x74, 0x65, 0x64, 0x09, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x6C,
+            0x6F, 0x70, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x70, 0x61, 0x74, 0x68, 0x0E, 0x00, 0x09, 0x00, 0x00, 0x00,
+            0x00, 0x03, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+            0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03,
+            0x00, 0x00, 0x00, 0x08, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00,
+            0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x21, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00,
+            0x00, 0x06, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x00, 0x03, 0x00,
+            0x00, 0x00, 0x00, 0x02, 0x69, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00,
+            0x00, 0x05, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F,
+            0x6E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6E, 0x61, 0x6D, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x6D,
+            0x61, 0x72, 0x6B, 0x6F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x01, 0x00, 0x00, 0x00, 0x00,
+            0x1D, 0x03, 0x00, 0x00, 0x00, 0x00, 0x09, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x02, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x6B, 0x6E, 0x6F, 0x77,
+            0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03,
+            0x00, 0x00, 0x00, 0x00, 0x05, 0x76, 0x61, 0x64, 0x61, 0x73, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6A, 0x6F,
+            0x73, 0x68, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x6C, 0x6F, 0x70, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x70,
+            0x61, 0x74, 0x68, 0x0E, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x11,
+            0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE,
+            0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F,
+            0x6E, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72,
+            0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x00, 0x00,
+            0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x0A, 0x00, 0x00,
+            0x00, 0x00, 0x04, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x69, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00,
+            0x05, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x03, 0x00, 0x00, 0x00,
+            0x00, 0x08, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6E, 0x61,
+            0x6D, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x72, 0x69, 0x70, 0x70, 0x6C, 0x65, 0x03, 0x00, 0x00, 0x00,
+            0x00, 0x04, 0x6C, 0x61, 0x6E, 0x67, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6A, 0x61, 0x76, 0x61, 0x03, 0x00,
+            0x00, 0x00, 0x00, 0x09, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x02, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E,
+            0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x09, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00,
+            0x00, 0x06, 0x6E, 0x6F, 0x62, 0x6F, 0x64, 0x79, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x70, 0x61, 0x74, 0x68,
+            0x0E, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x11, 0x00, 0x01, 0x00,
+            0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x11, 0x00,
+            0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01,
+            0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61,
+            0x72, 0x65, 0xFE, 0x01, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x00, 0x00, 0x00,
+            0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x0A, 0x00, 0x00, 0x00,
+            0x00, 0x04, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x69, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03,
+            0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x03, 0x00, 0x00, 0x00, 0x00,
+            0x08, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6E, 0x61, 0x6D,
+            0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x6C, 0x6F, 0x70, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6C, 0x61,
+            0x6E, 0x67, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6A, 0x61, 0x76, 0x61, 0x03, 0x00, 0x00, 0x00, 0x00, 0x09,
+            0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65,
+            0x61, 0x74, 0x65, 0x64, 0x09, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x6E, 0x6F,
+            0x62, 0x6F, 0x64, 0x79, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x70, 0x61, 0x74, 0x68, 0x0E, 0x00, 0x09, 0x00,
+            0x00, 0x00, 0x00, 0x03, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
+            0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00,
+            0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00,
+            0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0xFE, 0x01,
+            0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00,
+            0x00, 0x00, 0x00, 0x06, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x00,
+            0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x69, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x00, 0x03, 0x00,
+            0x00, 0x00, 0x00, 0x05, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72,
+            0x73, 0x6F, 0x6E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6E, 0x61, 0x6D, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00,
+            0x05, 0x6D, 0x61, 0x72, 0x6B, 0x6F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x01, 0x00, 0x00,
+            0x00, 0x00, 0x1D, 0x03, 0x00, 0x00, 0x00, 0x00, 0x09, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74,
+            0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x6B, 0x6E,
+            0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x09, 0x00, 0x00, 0x00, 0x00,
+            0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x76, 0x61, 0x64, 0x61, 0x73, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04,
+            0x6A, 0x6F, 0x73, 0x68, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x6C, 0x6F, 0x70, 0x03, 0x00, 0x00, 0x00, 0x00,
+            0x04, 0x70, 0x61, 0x74, 0x68, 0x0E, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0B, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00,
+            0x03, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F,
+            0x6E, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72,
+            0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x70,
+            0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A,
+            0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x0A,
+            0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x69, 0x64, 0x01, 0x00, 0x00,
+            0x00, 0x00, 0x03, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x03, 0x00,
+            0x00, 0x00, 0x00, 0x08, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04,
+            0x6E, 0x61, 0x6D, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x6C, 0x6F, 0x70, 0x03, 0x00, 0x00, 0x00, 0x00,
+            0x04, 0x6C, 0x61, 0x6E, 0x67, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6A, 0x61, 0x76, 0x61, 0x03, 0x00, 0x00,
+            0x00, 0x00, 0x09, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64,
+            0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x09, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00,
+            0x06, 0x6E, 0x6F, 0x62, 0x6F, 0x64, 0x79, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x70, 0x61, 0x74, 0x68, 0x0E,
+            0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x11, 0x00, 0x01, 0x00, 0x00,
+            0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x11, 0x00, 0x01,
+            0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x11,
+            0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72,
+            0x65, 0xFE, 0x01, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x00, 0x00, 0x00, 0x00,
+            0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x00,
+            0x04, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x69, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20,
+            0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06,
+            0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6E, 0x61, 0x6D, 0x65, 0x03, 0x00,
+            0x00, 0x00, 0x00, 0x05, 0x76, 0x61, 0x64, 0x61, 0x73, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65,
+            0x01, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x03, 0x00, 0x00, 0x00, 0x00, 0x09, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F,
+            0x75, 0x6E, 0x74, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00,
+            0x0F, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x09, 0x00,
+            0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x6E, 0x6F, 0x62, 0x6F, 0x64, 0x79, 0x03, 0x00,
+            0x00, 0x00, 0x00, 0x04, 0x70, 0x61, 0x74, 0x68, 0x0E, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0B, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+            0x00, 0x00, 0x00, 0x03, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65,
+            0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06,
+            0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+            0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x01, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x76, 0x65, 0x72, 0x74,
+            0x65, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x69, 0x64,
+            0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x6C, 0x61, 0x62, 0x65,
+            0x6C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x03, 0x00, 0x00, 0x00, 0x00,
+            0x04, 0x6E, 0x61, 0x6D, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6A, 0x6F, 0x73, 0x68, 0x03, 0x00, 0x00,
+            0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00, 0x09,
+            0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65,
+            0x61, 0x74, 0x65, 0x64, 0x09, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x72, 0x69,
+            0x70, 0x70, 0x6C, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x6C, 0x6F, 0x70, 0x03, 0x00, 0x00, 0x00, 0x00,
+            0x04, 0x70, 0x61, 0x74, 0x68, 0x0E, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0B, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00,
+            0x03, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F,
+            0x6E, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72,
+            0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x70,
+            0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A,
+            0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x0A,
+            0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x69, 0x64, 0x01, 0x00, 0x00,
+            0x00, 0x00, 0x03, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x03, 0x00,
+            0x00, 0x00, 0x00, 0x08, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04,
+            0x6E, 0x61, 0x6D, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x6C, 0x6F, 0x70, 0x03, 0x00, 0x00, 0x00, 0x00,
+            0x04, 0x6C, 0x61, 0x6E, 0x67, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6A, 0x61, 0x76, 0x61, 0x03, 0x00, 0x00,
+            0x00, 0x00, 0x09, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64,
+            0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x09, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00,
+            0x06, 0x6E, 0x6F, 0x62, 0x6F, 0x64, 0x79, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x70, 0x61, 0x74, 0x68, 0x0E,
+            0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x11, 0x00, 0x01, 0x00, 0x00,
+            0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0xFE, 0x01, 0x11,
+            0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE,
+            0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x73, 0x6F, 0x66, 0x74, 0x77,
+            0x61, 0x72, 0x65, 0xFE, 0x01, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x00, 0x00,
+            0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x0A, 0x00, 0x00,
+            0x00, 0x00, 0x04, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x69, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00,
+            0x02, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x03, 0x00, 0x00, 0x00,
+            0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6E, 0x61, 0x6D, 0x65,
+            0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x76, 0x61, 0x64, 0x61, 0x73, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x61,
+            0x67, 0x65, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x03, 0x00, 0x00, 0x00, 0x00, 0x09, 0x65, 0x64, 0x67, 0x65,
+            0x43, 0x6F, 0x75, 0x6E, 0x74, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00,
+            0x00, 0x00, 0x0F, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64,
+            0x09, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x6E, 0x6F, 0x62, 0x6F, 0x64, 0x79,
+            0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x70, 0x61, 0x74, 0x68, 0x0E, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03,
+            0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08,
+            0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
+            0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00,
+            0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x21, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06,
+            0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00,
+            0x00, 0x02, 0x69, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05,
+            0x6C, 0x61, 0x62, 0x65, 0x6C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x03,
+            0x00, 0x00, 0x00, 0x00, 0x04, 0x6E, 0x61, 0x6D, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6A, 0x6F, 0x73,
+            0x68, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, 0x03, 0x00,
+            0x00, 0x00, 0x00, 0x09, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x02, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E,
+            0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x09, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00,
+            0x00, 0x06, 0x72, 0x69, 0x70, 0x70, 0x6C, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x6C, 0x6F, 0x70, 0x03,
+            0x00, 0x00, 0x00, 0x00, 0x04, 0x70, 0x61, 0x74, 0x68, 0x0E, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0B,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
+            0x00, 0x00, 0x00, 0x00, 0x03, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x73,
+            0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+            0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+            0x04, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x21, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x76,
+            0x65, 0x72, 0x74, 0x65, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
+            0x02, 0x69, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x6C,
+            0x61, 0x62, 0x65, 0x6C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x08, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65,
+            0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6E, 0x61, 0x6D, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x72, 0x69,
+            0x70, 0x70, 0x6C, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6C, 0x61, 0x6E, 0x67, 0x03, 0x00, 0x00, 0x00,
+            0x00, 0x04, 0x6A, 0x61, 0x76, 0x61, 0x03, 0x00, 0x00, 0x00, 0x00, 0x09, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F,
+            0x75, 0x6E, 0x74, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00,
+            0x0F, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x09, 0x00,
+            0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x6E, 0x6F, 0x62, 0x6F, 0x64, 0x79, 0x03, 0x00,
+            0x00, 0x00, 0x00, 0x04, 0x70, 0x61, 0x74, 0x68, 0x0E, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0B, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+            0x00, 0x00, 0x00, 0x03, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x73, 0x6F,
+            0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+            0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05,
+            0x00, 0x00, 0x00, 0x08, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0xFE, 0x01, 0x21, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06,
+            0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00,
+            0x00, 0x02, 0x69, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05,
+            0x6C, 0x61, 0x62, 0x65, 0x6C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x08, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72,
+            0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6E, 0x61, 0x6D, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x6C,
+            0x6F, 0x70, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6C, 0x61, 0x6E, 0x67, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04,
+            0x6A, 0x61, 0x76, 0x61, 0x03, 0x00, 0x00, 0x00, 0x00, 0x09, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E,
+            0x74, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x6B,
+            0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x09, 0x00, 0x00, 0x00,
+            0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x6E, 0x6F, 0x62, 0x6F, 0x64, 0x79, 0x03, 0x00, 0x00, 0x00,
+            0x00, 0x04, 0x70, 0x61, 0x74, 0x68, 0x0E, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0B, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+            0x00, 0x03, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x73, 0x6F, 0x66, 0x74,
+            0x77, 0x61, 0x72, 0x65, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06,
+            0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
+            0x00, 0x08, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0xFE, 0x01, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x01, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x76, 0x65,
+            0x72, 0x74, 0x65, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02,
+            0x69, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x6C, 0x61,
+            0x62, 0x65, 0x6C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x03, 0x00, 0x00,
+            0x00, 0x00, 0x04, 0x6E, 0x61, 0x6D, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x6D, 0x61, 0x72, 0x6B, 0x6F,
+            0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x03, 0x00, 0x00,
+            0x00, 0x00, 0x09, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64,
+            0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00,
+            0x05, 0x76, 0x61, 0x64, 0x61, 0x73, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6A, 0x6F, 0x73, 0x68, 0x03, 0x00,
+            0x00, 0x00, 0x00, 0x03, 0x6C, 0x6F, 0x70, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x70, 0x61, 0x74, 0x68, 0x0E,
+            0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x11, 0x00, 0x01, 0x00, 0x00,
+            0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0xFE, 0x01, 0x11,
+            0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE,
+            0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F,
+            0x6E, 0xFE, 0x01, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x00, 0x00, 0x00, 0x00,
+            0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x00,
+            0x04, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x69, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x20,
+            0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x08,
+            0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6E, 0x61, 0x6D, 0x65,
+            0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x6C, 0x6F, 0x70, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6C, 0x61, 0x6E,
+            0x67, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6A, 0x61, 0x76, 0x61, 0x03, 0x00, 0x00, 0x00, 0x00, 0x09, 0x65,
+            0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+            0x03, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61,
+            0x74, 0x65, 0x64, 0x09, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x6E, 0x6F, 0x62,
+            0x6F, 0x64, 0x79, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x70, 0x61, 0x74, 0x68, 0x0E, 0x00, 0x09, 0x00, 0x00,
+            0x00, 0x00, 0x03, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
+            0x00, 0x00, 0x08, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00,
+            0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x11, 0x00, 0x01,
+            0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0xFE,
+            0x01, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03,
+            0x00, 0x00, 0x00, 0x00, 0x06, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20,
+            0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x69, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x00, 0x03,
+            0x00, 0x00, 0x00, 0x00, 0x05, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65,
+            0x72, 0x73, 0x6F, 0x6E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6E, 0x61, 0x6D, 0x65, 0x03, 0x00, 0x00, 0x00,
+            0x00, 0x04, 0x6A, 0x6F, 0x73, 0x68, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x01, 0x00, 0x00,
+            0x00, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00, 0x09, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74,
+            0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x6B, 0x6E,
+            0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x09, 0x00, 0x00, 0x00, 0x00,
+            0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x72, 0x69, 0x70, 0x70, 0x6C, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00,
+            0x03, 0x6C, 0x6F, 0x70, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x70, 0x61, 0x74, 0x68, 0x0E, 0x00, 0x09, 0x00,
+            0x00, 0x00, 0x00, 0x03, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04,
+            0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00,
+            0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0xFE, 0x01, 0x11, 0x00,
+            0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01,
+            0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00,
+            0x00, 0x00, 0x00, 0x06, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x00,
+            0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x69, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x00, 0x03, 0x00,
+            0x00, 0x00, 0x00, 0x05, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72,
+            0x73, 0x6F, 0x6E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6E, 0x61, 0x6D, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00,
+            0x05, 0x6D, 0x61, 0x72, 0x6B, 0x6F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x01, 0x00, 0x00,
+            0x00, 0x00, 0x1D, 0x03, 0x00, 0x00, 0x00, 0x00, 0x09, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74,
+            0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x6B, 0x6E,
+            0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x09, 0x00, 0x00, 0x00, 0x00,
+            0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x76, 0x61, 0x64, 0x61, 0x73, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04,
+            0x6A, 0x6F, 0x73, 0x68, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x6C, 0x6F, 0x70, 0x03, 0x00, 0x00, 0x00, 0x00,
+            0x04, 0x70, 0x61, 0x74, 0x68, 0x0E, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0B, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00,
+            0x03, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F,
+            0x6E, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x73, 0x6F, 0x66,
+            0x74, 0x77, 0x61, 0x72, 0x65, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+            0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x01, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x76, 0x65, 0x72, 0x74, 0x65,
+            0x78, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x69, 0x64, 0x01,
+            0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x6C, 0x61, 0x62, 0x65, 0x6C,
+            0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04,
+            0x6E, 0x61, 0x6D, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6A, 0x6F, 0x73, 0x68, 0x03, 0x00, 0x00, 0x00,
+            0x00, 0x03, 0x61, 0x67, 0x65, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00, 0x09, 0x65,
+            0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+            0x03, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61,
+            0x74, 0x65, 0x64, 0x09, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x72, 0x69, 0x70,
+            0x70, 0x6C, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x6C, 0x6F, 0x70, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04,
+            0x70, 0x61, 0x74, 0x68, 0x0E, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03,
+            0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E,
+            0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x73, 0x6F, 0x66, 0x74,
+            0x77, 0x61, 0x72, 0x65, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06,
+            0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+            0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78,
+            0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x69, 0x64, 0x01, 0x00,
+            0x00, 0x00, 0x00, 0x06, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x03,
+            0x00, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6E,
+            0x61, 0x6D, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x70, 0x65, 0x74, 0x65, 0x72, 0x03, 0x00, 0x00, 0x00,
+            0x00, 0x03, 0x61, 0x67, 0x65, 0x01, 0x00, 0x00, 0x00, 0x00, 0x23, 0x03, 0x00, 0x00, 0x00, 0x00, 0x09, 0x65,
+            0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+            0x03, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61,
+            0x74, 0x65, 0x64, 0x09, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x6C, 0x6F, 0x70,
+            0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x70, 0x61, 0x74, 0x68, 0x0E, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03,
+            0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06,
+            0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
+            0x00, 0x08, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00,
+            0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x21, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06,
+            0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00,
+            0x00, 0x02, 0x69, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05,
+            0x6C, 0x61, 0x62, 0x65, 0x6C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x08, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72,
+            0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6E, 0x61, 0x6D, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x6C,
+            0x6F, 0x70, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6C, 0x61, 0x6E, 0x67, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04,
+            0x6A, 0x61, 0x76, 0x61, 0x03, 0x00, 0x00, 0x00, 0x00, 0x09, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E,
+            0x74, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x6B,
+            0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x09, 0x00, 0x00, 0x00,
+            0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x6E, 0x6F, 0x62, 0x6F, 0x64, 0x79, 0x03, 0x00, 0x00, 0x00,
+            0x00, 0x04, 0x70, 0x61, 0x74, 0x68, 0x0E, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0B, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+            0x00, 0x03, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73,
+            0x6F, 0x6E, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65,
+            0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08,
+            0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0xFE, 0x01, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x01, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x76, 0x65, 0x72, 0x74,
+            0x65, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x69, 0x64,
+            0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x6C, 0x61, 0x62, 0x65,
+            0x6C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x03, 0x00, 0x00, 0x00, 0x00,
+            0x04, 0x6E, 0x61, 0x6D, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x76, 0x61, 0x64, 0x61, 0x73, 0x03, 0x00,
+            0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x03, 0x00, 0x00, 0x00, 0x00,
+            0x09, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72,
+            0x65, 0x61, 0x74, 0x65, 0x64, 0x09, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x6E,
+            0x6F, 0x62, 0x6F, 0x64, 0x79, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x70, 0x61, 0x74, 0x68, 0x0E, 0x00, 0x09,
+            0x00, 0x00, 0x00, 0x00, 0x03, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+            0x04, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00,
+            0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x11, 0x00, 0x01,
+            0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x21,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00,
+            0x00, 0x00, 0x06, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x00, 0x03,
+            0x00, 0x00, 0x00, 0x00, 0x02, 0x69, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x00, 0x03, 0x00, 0x00,
+            0x00, 0x00, 0x05, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73,
+            0x6F, 0x6E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6E, 0x61, 0x6D, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04,
+            0x6A, 0x6F, 0x73, 0x68, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x01, 0x00, 0x00, 0x00, 0x00,
+            0x20, 0x03, 0x00, 0x00, 0x00, 0x00, 0x09, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x02, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x6B, 0x6E, 0x6F, 0x77,
+            0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x09, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03,
+            0x00, 0x00, 0x00, 0x00, 0x06, 0x72, 0x69, 0x70, 0x70, 0x6C, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x6C,
+            0x6F, 0x70, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x70, 0x61, 0x74, 0x68, 0x0E, 0x00, 0x09, 0x00, 0x00, 0x00,
+            0x00, 0x03, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+            0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
+            0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00,
+            0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x21, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06,
+            0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00,
+            0x00, 0x02, 0x69, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05,
+            0x6C, 0x61, 0x62, 0x65, 0x6C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x08, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72,
+            0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6E, 0x61, 0x6D, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x72,
+            0x69, 0x70, 0x70, 0x6C, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6C, 0x61, 0x6E, 0x67, 0x03, 0x00, 0x00,
+            0x00, 0x00, 0x04, 0x6A, 0x61, 0x76, 0x61, 0x03, 0x00, 0x00, 0x00, 0x00, 0x09, 0x65, 0x64, 0x67, 0x65, 0x43,
+            0x6F, 0x75, 0x6E, 0x74, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00,
+            0x00, 0x0F, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x09,
+            0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x6E, 0x6F, 0x62, 0x6F, 0x64, 0x79, 0x03,
+            0x00, 0x00, 0x00, 0x00, 0x04, 0x70, 0x61, 0x74, 0x68, 0x0E, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0B,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
+            0x00, 0x00, 0x00, 0x00, 0x03, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x73,
+            0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
+            0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+            0x05, 0x00, 0x00, 0x00, 0x08, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0xFE, 0x01, 0x21, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00,
+            0x06, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x00, 0x03, 0x00, 0x00,
+            0x00, 0x00, 0x02, 0x69, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
+            0x05, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x08, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61,
+            0x72, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6E, 0x61, 0x6D, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03,
+            0x6C, 0x6F, 0x70, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6C, 0x61, 0x6E, 0x67, 0x03, 0x00, 0x00, 0x00, 0x00,
+            0x04, 0x6A, 0x61, 0x76, 0x61, 0x03, 0x00, 0x00, 0x00, 0x00, 0x09, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75,
+            0x6E, 0x74, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0F,
+            0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x09, 0x00, 0x00,
+            0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x6E, 0x6F, 0x62, 0x6F, 0x64, 0x79, 0x03, 0x00, 0x00,
+            0x00, 0x00, 0x04, 0x70, 0x61, 0x74, 0x68, 0x0E, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0B, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+            0x00, 0x00, 0x03, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x73, 0x6F, 0x66,
+            0x74, 0x77, 0x61, 0x72, 0x65, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+            0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
+            0x00, 0x00, 0x08, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0xFE, 0x01, 0x21, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x76,
+            0x65, 0x72, 0x74, 0x65, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
+            0x02, 0x69, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x6C,
+            0x61, 0x62, 0x65, 0x6C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x03, 0x00,
+            0x00, 0x00, 0x00, 0x04, 0x6E, 0x61, 0x6D, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x6D, 0x61, 0x72, 0x6B,
+            0x6F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x03, 0x00,
+            0x00, 0x00, 0x00, 0x09, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x02, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E,
+            0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00,
+            0x00, 0x05, 0x76, 0x61, 0x64, 0x61, 0x73, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6A, 0x6F, 0x73, 0x68, 0x03,
+            0x00, 0x00, 0x00, 0x00, 0x03, 0x6C, 0x6F, 0x70, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x70, 0x61, 0x74, 0x68,
+            0x0E, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x11, 0x00, 0x01, 0x00,
+            0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0xFE, 0x01,
+            0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E,
+            0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73,
+            0x6F, 0x6E, 0xFE, 0x01, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x00, 0x00, 0x00,
+            0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x0A, 0x00, 0x00, 0x00,
+            0x00, 0x04, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x69, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
+            0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x03, 0x00, 0x00, 0x00, 0x00,
+            0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6E, 0x61, 0x6D, 0x65, 0x03,
+            0x00, 0x00, 0x00, 0x00, 0x05, 0x6D, 0x61, 0x72, 0x6B, 0x6F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x61, 0x67,
+            0x65, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x03, 0x00, 0x00, 0x00, 0x00, 0x09, 0x65, 0x64, 0x67, 0x65, 0x43,
+            0x6F, 0x75, 0x6E, 0x74, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00,
+            0x00, 0x0F, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x09,
+            0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x76, 0x61, 0x64, 0x61, 0x73, 0x03, 0x00,
+            0x00, 0x00, 0x00, 0x04, 0x6A, 0x6F, 0x73, 0x68, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x6C, 0x6F, 0x70, 0x03,
+            0x00, 0x00, 0x00, 0x00, 0x04, 0x70, 0x61, 0x74, 0x68, 0x0E, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0B,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
+            0x00, 0x00, 0x00, 0x00, 0x03, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x70,
+            0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+            0x08, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+            0x01, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x21, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x76,
+            0x65, 0x72, 0x74, 0x65, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
+            0x02, 0x69, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x6C,
+            0x61, 0x62, 0x65, 0x6C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x03, 0x00,
+            0x00, 0x00, 0x00, 0x04, 0x6E, 0x61, 0x6D, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6A, 0x6F, 0x73, 0x68,
+            0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, 0x03, 0x00, 0x00,
+            0x00, 0x00, 0x09, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64,
+            0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x09, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00,
+            0x06, 0x72, 0x69, 0x70, 0x70, 0x6C, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x6C, 0x6F, 0x70, 0x03, 0x00,
+            0x00, 0x00, 0x00, 0x04, 0x70, 0x61, 0x74, 0x68, 0x0E, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0B, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+            0x00, 0x00, 0x00, 0x03, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65,
+            0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08,
+            0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04,
+            0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x01, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x76, 0x65,
+            0x72, 0x74, 0x65, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02,
+            0x69, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x6C, 0x61,
+            0x62, 0x65, 0x6C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x03, 0x00, 0x00,
+            0x00, 0x00, 0x04, 0x6E, 0x61, 0x6D, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x70, 0x65, 0x74, 0x65, 0x72,
+            0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x01, 0x00, 0x00, 0x00, 0x00, 0x23, 0x03, 0x00, 0x00,
+            0x00, 0x00, 0x09, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64,
+            0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x09, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00,
+            0x03, 0x6C, 0x6F, 0x70, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x70, 0x61, 0x74, 0x68, 0x0E, 0x00, 0x09, 0x00,
+            0x00, 0x00, 0x00, 0x03, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06,
+            0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00,
+            0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0xFE, 0x01, 0x11, 0x00,
+            0x01, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0xFE, 0x01
+        };
+
+        public static readonly byte[] SmallGraphSON3ResponseMessageBytes =
+        {
+            0x7B, 0x22, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x22, 0x3A, 0x22, 0x32, 0x61, 0x34, 0x31,
+            0x65, 0x66, 0x65, 0x34, 0x2D, 0x62, 0x37, 0x32, 0x63, 0x2D, 0x34, 0x30, 0x32, 0x30, 0x2D, 0x62, 0x34, 0x66,
+            0x62, 0x2D, 0x34, 0x64, 0x35, 0x32, 0x32, 0x63, 0x30, 0x36, 0x66, 0x66, 0x31, 0x66, 0x22, 0x2C, 0x22, 0x73,
+            0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x6D, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x3A,
+            0x22, 0x22, 0x2C, 0x22, 0x63, 0x6F, 0x64, 0x65, 0x22, 0x3A, 0x32, 0x30, 0x30, 0x2C, 0x22, 0x61, 0x74, 0x74,
+            0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B,
+            0x22, 0x68, 0x6F, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x2F, 0x31, 0x37, 0x32, 0x2E, 0x31, 0x37, 0x2E, 0x30, 0x2E,
+            0x31, 0x3A, 0x34, 0x31, 0x38, 0x30, 0x38, 0x22, 0x5D, 0x7D, 0x7D, 0x2C, 0x22, 0x72, 0x65, 0x73, 0x75, 0x6C,
+            0x74, 0x22, 0x3A, 0x7B, 0x22, 0x64, 0x61, 0x74, 0x61, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x72, 0x61,
+            0x76, 0x65, 0x72, 0x73, 0x65, 0x72, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B,
+            0x22, 0x62, 0x75, 0x6C, 0x6B, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31,
+            0x7D, 0x2C, 0x22, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x36, 0x7D, 0x7D, 0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x6D, 0x65, 0x74, 0x61, 0x22, 0x3A, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x7D, 0x7D
+        };
+
+        public static readonly byte[] BigGraphSON3ResponseMessageBytes =
+        {
+            0x7B, 0x22, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x22, 0x3A, 0x22, 0x35, 0x64, 0x38, 0x31,
+            0x39, 0x31, 0x31, 0x37, 0x2D, 0x37, 0x63, 0x32, 0x36, 0x2D, 0x34, 0x62, 0x39, 0x64, 0x2D, 0x61, 0x39, 0x36,
+            0x65, 0x2D, 0x62, 0x33, 0x30, 0x61, 0x38, 0x37, 0x32, 0x36, 0x31, 0x37, 0x37, 0x39, 0x22, 0x2C, 0x22, 0x73,
+            0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x6D, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x3A,
+            0x22, 0x22, 0x2C, 0x22, 0x63, 0x6F, 0x64, 0x65, 0x22, 0x3A, 0x32, 0x30, 0x30, 0x2C, 0x22, 0x61, 0x74, 0x74,
+            0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B,
+            0x22, 0x68, 0x6F, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x2F, 0x31, 0x37, 0x32, 0x2E, 0x31, 0x37, 0x2E, 0x30, 0x2E,
+            0x31, 0x3A, 0x34, 0x31, 0x35, 0x30, 0x34, 0x22, 0x5D, 0x7D, 0x7D, 0x2C, 0x22, 0x72, 0x65, 0x73, 0x75, 0x6C,
+            0x74, 0x22, 0x3A, 0x7B, 0x22, 0x64, 0x61, 0x74, 0x61, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x72, 0x61,
+            0x76, 0x65, 0x72, 0x73, 0x65, 0x72, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B,
+            0x22, 0x62, 0x75, 0x6C, 0x6B, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31,
+            0x7D, 0x2C, 0x22, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x5B, 0x22, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x69, 0x64, 0x22, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x6C, 0x61, 0x62,
+            0x65, 0x6C, 0x22, 0x7D, 0x2C, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x2C, 0x22, 0x6E, 0x61, 0x6D,
+            0x65, 0x22, 0x2C, 0x22, 0x6D, 0x61, 0x72, 0x6B, 0x6F, 0x22, 0x2C, 0x22, 0x61, 0x67, 0x65, 0x22, 0x2C, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x32, 0x39, 0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x65, 0x64,
+            0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22,
+            0x3A, 0x33, 0x7D, 0x2C, 0x22, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74,
+            0x65, 0x64, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69,
+            0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x76, 0x61, 0x64,
+            0x61, 0x73, 0x22, 0x2C, 0x22, 0x6A, 0x6F, 0x73, 0x68, 0x22, 0x2C, 0x22, 0x6C, 0x6F, 0x70, 0x22, 0x5D, 0x7D,
+            0x2C, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x50, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B,
+            0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D,
+            0x5D, 0x7D, 0x2C, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56,
+            0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22,
+            0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E,
+            0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22,
+            0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x2C,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78,
+            0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C,
+            0x22, 0x3A, 0x22, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22,
+            0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22,
+            0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x2C,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x72, 0x61, 0x76, 0x65, 0x72,
+            0x73, 0x65, 0x72, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x62, 0x75,
+            0x6C, 0x6B, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E,
+            0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x76,
+            0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x22, 0x69, 0x64, 0x22, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x34, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54,
+            0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22,
+            0x7D, 0x2C, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x2C, 0x22, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x2C,
+            0x22, 0x6A, 0x6F, 0x73, 0x68, 0x22, 0x2C, 0x22, 0x61, 0x67, 0x65, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x32, 0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F,
+            0x75, 0x6E, 0x74, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49,
+            0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C,
+            0x22, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0x2C,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x72, 0x69, 0x70, 0x70, 0x6C, 0x65, 0x22,
+            0x2C, 0x22, 0x6C, 0x6F, 0x70, 0x22, 0x5D, 0x7D, 0x2C, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x50, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x73, 0x22, 0x3A, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22,
+            0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B,
+            0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74,
+            0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74,
+            0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73,
+            0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70,
+            0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65,
+            0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22,
+            0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33,
+            0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72,
+            0x65, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56,
+            0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22,
+            0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E,
+            0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x34, 0x7D, 0x2C, 0x22,
+            0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x5D,
+            0x7D, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x54, 0x72, 0x61, 0x76, 0x65, 0x72, 0x73, 0x65, 0x72, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x62, 0x75, 0x6C, 0x6B, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70,
+            0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x69, 0x64, 0x22, 0x7D, 0x2C,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22,
+            0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x36, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22,
+            0x3A, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x7D, 0x2C, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22,
+            0x2C, 0x22, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x2C, 0x22, 0x70, 0x65, 0x74, 0x65, 0x72, 0x22, 0x2C, 0x22, 0x61,
+            0x67, 0x65, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E,
+            0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x35, 0x7D, 0x5D,
+            0x7D, 0x2C, 0x22, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64,
+            0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x5B, 0x22, 0x6C, 0x6F, 0x70, 0x22, 0x5D, 0x7D, 0x2C, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x50, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x73, 0x22, 0x3A, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22,
+            0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B,
+            0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74,
+            0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74,
+            0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73,
+            0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70,
+            0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65,
+            0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22,
+            0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33,
+            0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72,
+            0x65, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56,
+            0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22,
+            0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E,
+            0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x36, 0x7D, 0x2C, 0x22,
+            0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x5D,
+            0x7D, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x54, 0x72, 0x61, 0x76, 0x65, 0x72, 0x73, 0x65, 0x72, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x62, 0x75, 0x6C, 0x6B, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70,
+            0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x69, 0x64, 0x22, 0x7D, 0x2C,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22,
+            0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22,
+            0x3A, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x7D, 0x2C, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22,
+            0x2C, 0x22, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x2C, 0x22, 0x6D, 0x61, 0x72, 0x6B, 0x6F, 0x22, 0x2C, 0x22, 0x61,
+            0x67, 0x65, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E,
+            0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x32, 0x39, 0x7D, 0x5D,
+            0x7D, 0x2C, 0x22, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x22, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64,
+            0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x5B, 0x22, 0x76, 0x61, 0x64, 0x61, 0x73, 0x22, 0x2C, 0x22, 0x6A, 0x6F, 0x73, 0x68, 0x22, 0x2C, 0x22, 0x6C,
+            0x6F, 0x70, 0x22, 0x5D, 0x7D, 0x2C, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x50, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22,
+            0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70,
+            0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x73, 0x22, 0x3A,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22,
+            0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F,
+            0x6E, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56,
+            0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22,
+            0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E,
+            0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x32, 0x7D, 0x2C, 0x22,
+            0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x2C,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78,
+            0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C,
+            0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x5D, 0x7D,
+            0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x72, 0x61,
+            0x76, 0x65, 0x72, 0x73, 0x65, 0x72, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B,
+            0x22, 0x62, 0x75, 0x6C, 0x6B, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31,
+            0x7D, 0x2C, 0x22, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x5B, 0x22, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x69, 0x64, 0x22, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x35, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x6C, 0x61, 0x62,
+            0x65, 0x6C, 0x22, 0x7D, 0x2C, 0x22, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x22, 0x2C, 0x22, 0x6E,
+            0x61, 0x6D, 0x65, 0x22, 0x2C, 0x22, 0x72, 0x69, 0x70, 0x70, 0x6C, 0x65, 0x22, 0x2C, 0x22, 0x6C, 0x61, 0x6E,
+            0x67, 0x22, 0x2C, 0x22, 0x6A, 0x61, 0x76, 0x61, 0x22, 0x5D, 0x7D, 0x2C, 0x22, 0x65, 0x64, 0x67, 0x65, 0x43,
+            0x6F, 0x75, 0x6E, 0x74, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D,
+            0x2C, 0x22, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22,
+            0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22,
+            0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x6E, 0x6F, 0x62, 0x6F, 0x64, 0x79,
+            0x22, 0x5D, 0x7D, 0x2C, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x50, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x7B, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70,
+            0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65,
+            0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x5B, 0x5D, 0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x73, 0x22, 0x3A, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22,
+            0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31,
+            0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22,
+            0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72,
+            0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64,
+            0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33,
+            0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x34, 0x7D, 0x2C, 0x22, 0x6C, 0x61,
+            0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x35, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A,
+            0x22, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x22, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x5D, 0x7D,
+            0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x72, 0x61,
+            0x76, 0x65, 0x72, 0x73, 0x65, 0x72, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B,
+            0x22, 0x62, 0x75, 0x6C, 0x6B, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31,
+            0x7D, 0x2C, 0x22, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x5B, 0x22, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x69, 0x64, 0x22, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x6C, 0x61, 0x62,
+            0x65, 0x6C, 0x22, 0x7D, 0x2C, 0x22, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x22, 0x2C, 0x22, 0x6E,
+            0x61, 0x6D, 0x65, 0x22, 0x2C, 0x22, 0x6C, 0x6F, 0x70, 0x22, 0x2C, 0x22, 0x6C, 0x61, 0x6E, 0x67, 0x22, 0x2C,
+            0x22, 0x6A, 0x61, 0x76, 0x61, 0x22, 0x5D, 0x7D, 0x2C, 0x22, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E,
+            0x74, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74,
+            0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x22, 0x6B,
+            0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0x2C, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x6E, 0x6F, 0x62, 0x6F, 0x64, 0x79, 0x22, 0x5D, 0x7D,
+            0x2C, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x50, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B,
+            0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D,
+            0x5D, 0x7D, 0x2C, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56,
+            0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22,
+            0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E,
+            0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22,
+            0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x2C,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78,
+            0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x34, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C,
+            0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70,
+            0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x73, 0x6F,
+            0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x22, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x2C,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x72, 0x61, 0x76, 0x65, 0x72,
+            0x73, 0x65, 0x72, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x62, 0x75,
+            0x6C, 0x6B, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E,
+            0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x76,
+            0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x22, 0x69, 0x64, 0x22, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54,
+            0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22,
+            0x7D, 0x2C, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x2C, 0x22, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x2C,
+            0x22, 0x6D, 0x61, 0x72, 0x6B, 0x6F, 0x22, 0x2C, 0x22, 0x61, 0x67, 0x65, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x32, 0x39, 0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x65, 0x64, 0x67, 0x65, 0x43,
+            0x6F, 0x75, 0x6E, 0x74, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D,
+            0x2C, 0x22, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22,
+            0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22,
+            0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x76, 0x61, 0x64, 0x61, 0x73, 0x22,
+            0x2C, 0x22, 0x6A, 0x6F, 0x73, 0x68, 0x22, 0x2C, 0x22, 0x6C, 0x6F, 0x70, 0x22, 0x5D, 0x7D, 0x2C, 0x22, 0x70,
+            0x61, 0x74, 0x68, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x50,
+            0x61, 0x74, 0x68, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x6C, 0x61,
+            0x62, 0x65, 0x6C, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65,
+            0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x5D, 0x7D, 0x2C,
+            0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22,
+            0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74,
+            0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22,
+            0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32,
+            0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62,
+            0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22,
+            0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x34, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22,
+            0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22,
+            0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F,
+            0x6E, 0x22, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x72, 0x61, 0x76, 0x65, 0x72, 0x73, 0x65, 0x72, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x62, 0x75, 0x6C, 0x6B, 0x22, 0x3A, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22,
+            0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78,
+            0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22,
+            0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22,
+            0x69, 0x64, 0x22, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49,
+            0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x7D, 0x2C, 0x22, 0x73, 0x6F,
+            0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x22, 0x2C, 0x22, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x2C, 0x22, 0x6C, 0x6F,
+            0x70, 0x22, 0x2C, 0x22, 0x6C, 0x61, 0x6E, 0x67, 0x22, 0x2C, 0x22, 0x6A, 0x61, 0x76, 0x61, 0x22, 0x5D, 0x7D,
+            0x2C, 0x22, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x22, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43,
+            0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B,
+            0x22, 0x6E, 0x6F, 0x62, 0x6F, 0x64, 0x79, 0x22, 0x5D, 0x7D, 0x2C, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x2C,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x50, 0x61, 0x74, 0x68, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x73, 0x22,
+            0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22,
+            0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22,
+            0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53,
+            0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x6F, 0x62, 0x6A, 0x65,
+            0x63, 0x74, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C,
+            0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22,
+            0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x32, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22,
+            0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22,
+            0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F,
+            0x6E, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56,
+            0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22,
+            0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E,
+            0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x22,
+            0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x22, 0x7D,
+            0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x54, 0x72, 0x61, 0x76, 0x65, 0x72, 0x73, 0x65, 0x72, 0x22, 0x2C, 0x22, 0x40, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x62, 0x75, 0x6C, 0x6B, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x69, 0x64, 0x22,
+            0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33,
+            0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x32, 0x7D, 0x2C, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x7D, 0x2C, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F,
+            0x6E, 0x22, 0x2C, 0x22, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x2C, 0x22, 0x76, 0x61, 0x64, 0x61, 0x73, 0x22, 0x2C,
+            0x22, 0x61, 0x67, 0x65, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x32, 0x37,
+            0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x22, 0x2C, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22,
+            0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41,
+            0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x5B, 0x22, 0x6E, 0x6F, 0x62, 0x6F, 0x64, 0x79, 0x22, 0x5D, 0x7D, 0x2C, 0x22, 0x70, 0x61, 0x74,
+            0x68, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x50, 0x61, 0x74,
+            0x68, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x6C, 0x61, 0x62, 0x65,
+            0x6C, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69,
+            0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D,
+            0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22,
+            0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x6F,
+            0x62, 0x6A, 0x65, 0x63, 0x74, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78,
+            0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x32, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C,
+            0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70,
+            0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65,
+            0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22,
+            0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x32,
+            0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22,
+            0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x72, 0x61, 0x76, 0x65, 0x72, 0x73, 0x65, 0x72, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x62, 0x75, 0x6C, 0x6B, 0x22, 0x3A, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22,
+            0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22,
+            0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x69, 0x64,
+            0x22, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74,
+            0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x34, 0x7D, 0x2C, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x7D, 0x2C, 0x22, 0x70, 0x65, 0x72, 0x73,
+            0x6F, 0x6E, 0x22, 0x2C, 0x22, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x2C, 0x22, 0x6A, 0x6F, 0x73, 0x68, 0x22, 0x2C,
+            0x22, 0x61, 0x67, 0x65, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x32,
+            0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x22, 0x2C, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22,
+            0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x22, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41,
+            0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x5B, 0x22, 0x72, 0x69, 0x70, 0x70, 0x6C, 0x65, 0x22, 0x2C, 0x22, 0x6C, 0x6F, 0x70, 0x22, 0x5D,
+            0x7D, 0x2C, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x50, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x7B, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22,
+            0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22,
+            0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D,
+            0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B,
+            0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49,
+            0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x32, 0x7D, 0x2C,
+            0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D,
+            0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65,
+            0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22,
+            0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65,
+            0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x34, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70,
+            0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x2C, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x72, 0x61, 0x76, 0x65, 0x72, 0x73,
+            0x65, 0x72, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x62, 0x75, 0x6C,
+            0x6B, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74,
+            0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x76, 0x65,
+            0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x22, 0x69, 0x64, 0x22, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22,
+            0x3A, 0x33, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22,
+            0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x7D,
+            0x2C, 0x22, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x22, 0x2C, 0x22, 0x6E, 0x61, 0x6D, 0x65, 0x22,
+            0x2C, 0x22, 0x6C, 0x6F, 0x70, 0x22, 0x2C, 0x22, 0x6C, 0x61, 0x6E, 0x67, 0x22, 0x2C, 0x22, 0x6A, 0x61, 0x76,
+            0x61, 0x22, 0x5D, 0x7D, 0x2C, 0x22, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x22, 0x2C, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x22, 0x6B, 0x6E, 0x6F, 0x77, 0x73,
+            0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70,
+            0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x5B, 0x22, 0x6E, 0x6F, 0x62, 0x6F, 0x64, 0x79, 0x22, 0x5D, 0x7D, 0x2C, 0x22, 0x70, 0x61,
+            0x74, 0x68, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x50, 0x61,
+            0x74, 0x68, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x6C, 0x61, 0x62,
+            0x65, 0x6C, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C,
+            0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B,
+            0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74,
+            0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x5D, 0x7D, 0x2C, 0x22,
+            0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65,
+            0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22,
+            0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65,
+            0x6C, 0x22, 0x3A, 0x22, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A,
+            0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x73, 0x6F, 0x66, 0x74,
+            0x77, 0x61, 0x72, 0x65, 0x22, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x2C, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x72, 0x61, 0x76, 0x65, 0x72, 0x73, 0x65,
+            0x72, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x62, 0x75, 0x6C, 0x6B,
+            0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36,
+            0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D,
+            0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x76, 0x65, 0x72,
+            0x74, 0x65, 0x78, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D,
+            0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x22, 0x69, 0x64, 0x22, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x32, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x7D, 0x2C,
+            0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x2C, 0x22, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x2C, 0x22, 0x76,
+            0x61, 0x64, 0x61, 0x73, 0x22, 0x2C, 0x22, 0x61, 0x67, 0x65, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70,
+            0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x32, 0x37, 0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75,
+            0x6E, 0x74, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E,
+            0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22,
+            0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0x2C, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22,
+            0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x6E, 0x6F, 0x62, 0x6F, 0x64, 0x79, 0x22, 0x5D,
+            0x7D, 0x2C, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x50, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x7B, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22,
+            0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22,
+            0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D,
+            0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B,
+            0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49,
+            0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C,
+            0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x22,
+            0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72,
+            0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64,
+            0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33,
+            0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x6C, 0x61,
+            0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x32, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A,
+            0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D,
+            0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x72, 0x61, 0x76, 0x65,
+            0x72, 0x73, 0x65, 0x72, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x62,
+            0x75, 0x6C, 0x6B, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49,
+            0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C,
+            0x22, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22,
+            0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x69, 0x64, 0x22, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x34, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C,
+            0x22, 0x7D, 0x2C, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x2C, 0x22, 0x6E, 0x61, 0x6D, 0x65, 0x22,
+            0x2C, 0x22, 0x6A, 0x6F, 0x73, 0x68, 0x22, 0x2C, 0x22, 0x61, 0x67, 0x65, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x32, 0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x65, 0x64, 0x67, 0x65, 0x43,
+            0x6F, 0x75, 0x6E, 0x74, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D,
+            0x2C, 0x22, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22,
+            0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22,
+            0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x72, 0x69, 0x70, 0x70, 0x6C, 0x65,
+            0x22, 0x2C, 0x22, 0x6C, 0x6F, 0x70, 0x22, 0x5D, 0x7D, 0x2C, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x50, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x22,
+            0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x73, 0x22, 0x3A,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65,
+            0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63,
+            0x74, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69,
+            0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x73,
+            0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73,
+            0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B,
+            0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49,
+            0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x34, 0x7D, 0x2C,
+            0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D,
+            0x5D, 0x7D, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x54, 0x72, 0x61, 0x76, 0x65, 0x72, 0x73, 0x65, 0x72, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x62, 0x75, 0x6C, 0x6B, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x69, 0x64, 0x22, 0x7D,
+            0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32,
+            0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x35, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x7D, 0x2C, 0x22, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61,
+            0x72, 0x65, 0x22, 0x2C, 0x22, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x2C, 0x22, 0x72, 0x69, 0x70, 0x70, 0x6C, 0x65,
+            0x22, 0x2C, 0x22, 0x6C, 0x61, 0x6E, 0x67, 0x22, 0x2C, 0x22, 0x6A, 0x61, 0x76, 0x61, 0x22, 0x5D, 0x7D, 0x2C,
+            0x22, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70,
+            0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72,
+            0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22,
+            0x6E, 0x6F, 0x62, 0x6F, 0x64, 0x79, 0x22, 0x5D, 0x7D, 0x2C, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x50, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x22,
+            0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x73, 0x22, 0x3A,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65,
+            0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63,
+            0x74, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69,
+            0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x73,
+            0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x34, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73,
+            0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B,
+            0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49,
+            0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x35, 0x7D, 0x2C,
+            0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x22,
+            0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x72, 0x61, 0x76, 0x65, 0x72, 0x73, 0x65, 0x72, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x62, 0x75, 0x6C, 0x6B, 0x22, 0x3A, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22,
+            0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22,
+            0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x69, 0x64,
+            0x22, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74,
+            0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x7D, 0x2C, 0x22, 0x73, 0x6F, 0x66, 0x74,
+            0x77, 0x61, 0x72, 0x65, 0x22, 0x2C, 0x22, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x2C, 0x22, 0x6C, 0x6F, 0x70, 0x22,
+            0x2C, 0x22, 0x6C, 0x61, 0x6E, 0x67, 0x22, 0x2C, 0x22, 0x6A, 0x61, 0x76, 0x61, 0x22, 0x5D, 0x7D, 0x2C, 0x22,
+            0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x22, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65,
+            0x61, 0x74, 0x65, 0x64, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x6E,
+            0x6F, 0x62, 0x6F, 0x64, 0x79, 0x22, 0x5D, 0x7D, 0x2C, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x50, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x73, 0x22, 0x3A, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22,
+            0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B,
+            0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74,
+            0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74,
+            0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73,
+            0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70,
+            0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x73, 0x6F,
+            0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22,
+            0x3A, 0x34, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F,
+            0x6E, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56,
+            0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22,
+            0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E,
+            0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x22,
+            0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x22, 0x7D,
+            0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x54, 0x72, 0x61, 0x76, 0x65, 0x72, 0x73, 0x65, 0x72, 0x22, 0x2C, 0x22, 0x40, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x62, 0x75, 0x6C, 0x6B, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x69, 0x64, 0x22,
+            0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33,
+            0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x7D, 0x2C, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F,
+            0x6E, 0x22, 0x2C, 0x22, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x2C, 0x22, 0x6D, 0x61, 0x72, 0x6B, 0x6F, 0x22, 0x2C,
+            0x22, 0x61, 0x67, 0x65, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x32, 0x39,
+            0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x22, 0x2C, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22,
+            0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x22, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41,
+            0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x5B, 0x22, 0x76, 0x61, 0x64, 0x61, 0x73, 0x22, 0x2C, 0x22, 0x6A, 0x6F, 0x73, 0x68, 0x22, 0x2C,
+            0x22, 0x6C, 0x6F, 0x70, 0x22, 0x5D, 0x7D, 0x2C, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x50, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x22, 0x40, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x73, 0x22, 0x3A, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D,
+            0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22,
+            0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x73,
+            0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74,
+            0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70,
+            0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x73, 0x6F, 0x66,
+            0x74, 0x77, 0x61, 0x72, 0x65, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x34, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E,
+            0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65,
+            0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69,
+            0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74,
+            0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x6C,
+            0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x5D, 0x7D,
+            0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x54, 0x72, 0x61, 0x76, 0x65, 0x72, 0x73, 0x65, 0x72, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x7B, 0x22, 0x62, 0x75, 0x6C, 0x6B, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54,
+            0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x69, 0x64, 0x22, 0x7D, 0x2C, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70,
+            0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x7D, 0x2C, 0x22, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65,
+            0x22, 0x2C, 0x22, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x2C, 0x22, 0x6C, 0x6F, 0x70, 0x22, 0x2C, 0x22, 0x6C, 0x61,
+            0x6E, 0x67, 0x22, 0x2C, 0x22, 0x6A, 0x61, 0x76, 0x61, 0x22, 0x5D, 0x7D, 0x2C, 0x22, 0x65, 0x64, 0x67, 0x65,
+            0x43, 0x6F, 0x75, 0x6E, 0x74, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33,
+            0x7D, 0x2C, 0x22, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64,
+            0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74,
+            0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x6E, 0x6F, 0x62, 0x6F, 0x64,
+            0x79, 0x22, 0x5D, 0x7D, 0x2C, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70,
+            0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x50, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x7B, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53,
+            0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22,
+            0x3A, 0x5B, 0x5D, 0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x73, 0x22, 0x3A, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22,
+            0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x33, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61,
+            0x72, 0x65, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B,
+            0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49,
+            0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x36, 0x7D, 0x2C,
+            0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D,
+            0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65,
+            0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22,
+            0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65,
+            0x6C, 0x22, 0x3A, 0x22, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x22, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D,
+            0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x54, 0x72, 0x61, 0x76, 0x65, 0x72, 0x73, 0x65, 0x72, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x7B, 0x22, 0x62, 0x75, 0x6C, 0x6B, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x5B, 0x22, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22,
+            0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x69, 0x64, 0x22, 0x7D, 0x2C, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22,
+            0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x34, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22,
+            0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x7D, 0x2C, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x2C, 0x22,
+            0x6E, 0x61, 0x6D, 0x65, 0x22, 0x2C, 0x22, 0x6A, 0x6F, 0x73, 0x68, 0x22, 0x2C, 0x22, 0x61, 0x67, 0x65, 0x22,
+            0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32,
+            0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x32, 0x7D, 0x5D, 0x7D, 0x2C, 0x22,
+            0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x22, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65,
+            0x61, 0x74, 0x65, 0x64, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x72,
+            0x69, 0x70, 0x70, 0x6C, 0x65, 0x22, 0x2C, 0x22, 0x6C, 0x6F, 0x70, 0x22, 0x5D, 0x7D, 0x2C, 0x22, 0x70, 0x61,
+            0x74, 0x68, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x50, 0x61,
+            0x74, 0x68, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x6C, 0x61, 0x62,
+            0x65, 0x6C, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C,
+            0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B,
+            0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74,
+            0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x5D, 0x7D, 0x2C, 0x22,
+            0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65,
+            0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22,
+            0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x34, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65,
+            0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x35, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x73,
+            0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x34, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73,
+            0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x72, 0x61, 0x76, 0x65, 0x72, 0x73, 0x65, 0x72, 0x22,
+            0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x62, 0x75, 0x6C, 0x6B, 0x22, 0x3A,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22,
+            0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70,
+            0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x76, 0x65, 0x72, 0x74, 0x65,
+            0x78, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70,
+            0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70,
+            0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x22, 0x69, 0x64, 0x22, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D,
+            0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x7D, 0x2C, 0x22, 0x70,
+            0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x2C, 0x22, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x2C, 0x22, 0x6D, 0x61, 0x72,
+            0x6B, 0x6F, 0x22, 0x2C, 0x22, 0x61, 0x67, 0x65, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x32, 0x39, 0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74,
+            0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36,
+            0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x22, 0x6B, 0x6E,
+            0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0x2C, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x76, 0x61, 0x64, 0x61, 0x73, 0x22, 0x2C, 0x22, 0x6A, 0x6F,
+            0x73, 0x68, 0x22, 0x2C, 0x22, 0x6C, 0x6F, 0x70, 0x22, 0x5D, 0x7D, 0x2C, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22,
+            0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x50, 0x61, 0x74, 0x68, 0x22,
+            0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x73,
+            0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74,
+            0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70,
+            0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22,
+            0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x6F, 0x62, 0x6A,
+            0x65, 0x63, 0x74, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x34, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A,
+            0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x73, 0x6F, 0x66, 0x74,
+            0x77, 0x61, 0x72, 0x65, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22,
+            0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31,
+            0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22,
+            0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x72, 0x61, 0x76, 0x65, 0x72, 0x73, 0x65, 0x72, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x62, 0x75, 0x6C, 0x6B, 0x22, 0x3A, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22,
+            0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22,
+            0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x69, 0x64,
+            0x22, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74,
+            0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x34, 0x7D, 0x2C, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x7D, 0x2C, 0x22, 0x70, 0x65, 0x72, 0x73,
+            0x6F, 0x6E, 0x22, 0x2C, 0x22, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x2C, 0x22, 0x6A, 0x6F, 0x73, 0x68, 0x22, 0x2C,
+            0x22, 0x61, 0x67, 0x65, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x32,
+            0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x22, 0x2C, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22,
+            0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x22, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41,
+            0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x5B, 0x22, 0x72, 0x69, 0x70, 0x70, 0x6C, 0x65, 0x22, 0x2C, 0x22, 0x6C, 0x6F, 0x70, 0x22, 0x5D,
+            0x7D, 0x2C, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x50, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x7B, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22,
+            0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22,
+            0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D,
+            0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B,
+            0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49,
+            0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x34, 0x7D, 0x2C,
+            0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D,
+            0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65,
+            0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22,
+            0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65,
+            0x6C, 0x22, 0x3A, 0x22, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x34, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A,
+            0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D,
+            0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x72, 0x61, 0x76, 0x65,
+            0x72, 0x73, 0x65, 0x72, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x62,
+            0x75, 0x6C, 0x6B, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49,
+            0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C,
+            0x22, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22,
+            0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x69, 0x64, 0x22, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x36, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C,
+            0x22, 0x7D, 0x2C, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x2C, 0x22, 0x6E, 0x61, 0x6D, 0x65, 0x22,
+            0x2C, 0x22, 0x70, 0x65, 0x74, 0x65, 0x72, 0x22, 0x2C, 0x22, 0x61, 0x67, 0x65, 0x22, 0x2C, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x35, 0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x65, 0x64, 0x67, 0x65,
+            0x43, 0x6F, 0x75, 0x6E, 0x74, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31,
+            0x7D, 0x2C, 0x22, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64,
+            0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74,
+            0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x6C, 0x6F, 0x70, 0x22, 0x5D,
+            0x7D, 0x2C, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x50, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x7B, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22,
+            0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22,
+            0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D,
+            0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B,
+            0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49,
+            0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x34, 0x7D, 0x2C,
+            0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D,
+            0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65,
+            0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22,
+            0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65,
+            0x6C, 0x22, 0x3A, 0x22, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x36, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A,
+            0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D,
+            0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x72, 0x61, 0x76, 0x65,
+            0x72, 0x73, 0x65, 0x72, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x62,
+            0x75, 0x6C, 0x6B, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49,
+            0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C,
+            0x22, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22,
+            0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x69, 0x64, 0x22, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C,
+            0x22, 0x7D, 0x2C, 0x22, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x22, 0x2C, 0x22, 0x6E, 0x61, 0x6D,
+            0x65, 0x22, 0x2C, 0x22, 0x6C, 0x6F, 0x70, 0x22, 0x2C, 0x22, 0x6C, 0x61, 0x6E, 0x67, 0x22, 0x2C, 0x22, 0x6A,
+            0x61, 0x76, 0x61, 0x22, 0x5D, 0x7D, 0x2C, 0x22, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x22,
+            0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34,
+            0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x22, 0x6B, 0x6E, 0x6F,
+            0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x6E, 0x6F, 0x62, 0x6F, 0x64, 0x79, 0x22, 0x5D, 0x7D, 0x2C, 0x22,
+            0x70, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x50, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x6C,
+            0x61, 0x62, 0x65, 0x6C, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22,
+            0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53,
+            0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x5D, 0x7D,
+            0x2C, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72,
+            0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64,
+            0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33,
+            0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x34, 0x7D, 0x2C, 0x22, 0x6C, 0x61,
+            0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A,
+            0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x73, 0x6F, 0x66, 0x74,
+            0x77, 0x61, 0x72, 0x65, 0x22, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x2C, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x72, 0x61, 0x76, 0x65, 0x72, 0x73, 0x65,
+            0x72, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x62, 0x75, 0x6C, 0x6B,
+            0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36,
+            0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D,
+            0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x76, 0x65, 0x72,
+            0x74, 0x65, 0x78, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D,
+            0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x22, 0x69, 0x64, 0x22, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x32, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x7D, 0x2C,
+            0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x2C, 0x22, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x2C, 0x22, 0x76,
+            0x61, 0x64, 0x61, 0x73, 0x22, 0x2C, 0x22, 0x61, 0x67, 0x65, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70,
+            0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x32, 0x37, 0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75,
+            0x6E, 0x74, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E,
+            0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22,
+            0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0x2C, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22,
+            0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x6E, 0x6F, 0x62, 0x6F, 0x64, 0x79, 0x22, 0x5D,
+            0x7D, 0x2C, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x50, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x7B, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22,
+            0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22,
+            0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D,
+            0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B,
+            0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49,
+            0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x34, 0x7D, 0x2C,
+            0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D,
+            0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65,
+            0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22,
+            0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65,
+            0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x32, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70,
+            0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x2C, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x72, 0x61, 0x76, 0x65, 0x72, 0x73,
+            0x65, 0x72, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x62, 0x75, 0x6C,
+            0x6B, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74,
+            0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x76, 0x65,
+            0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x22, 0x69, 0x64, 0x22, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22,
+            0x3A, 0x34, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22,
+            0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x7D,
+            0x2C, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x2C, 0x22, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x2C, 0x22,
+            0x6A, 0x6F, 0x73, 0x68, 0x22, 0x2C, 0x22, 0x61, 0x67, 0x65, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70,
+            0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x33, 0x32, 0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75,
+            0x6E, 0x74, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E,
+            0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x22,
+            0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0x2C, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22,
+            0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x72, 0x69, 0x70, 0x70, 0x6C, 0x65, 0x22, 0x2C,
+            0x22, 0x6C, 0x6F, 0x70, 0x22, 0x5D, 0x7D, 0x2C, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x50, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x22, 0x40, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x73, 0x22, 0x3A, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D,
+            0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22,
+            0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x73,
+            0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74,
+            0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70,
+            0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x34, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72,
+            0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D,
+            0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D,
+            0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74,
+            0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22,
+            0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32,
+            0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x34, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62,
+            0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D,
+            0x5D, 0x7D, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54,
+            0x72, 0x61, 0x76, 0x65, 0x72, 0x73, 0x65, 0x72, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22,
+            0x3A, 0x7B, 0x22, 0x62, 0x75, 0x6C, 0x6B, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22,
+            0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70,
+            0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x5B, 0x22, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70,
+            0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x69, 0x64, 0x22, 0x7D, 0x2C, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x35, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x6C,
+            0x61, 0x62, 0x65, 0x6C, 0x22, 0x7D, 0x2C, 0x22, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x22, 0x2C,
+            0x22, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x2C, 0x22, 0x72, 0x69, 0x70, 0x70, 0x6C, 0x65, 0x22, 0x2C, 0x22, 0x6C,
+            0x61, 0x6E, 0x67, 0x22, 0x2C, 0x22, 0x6A, 0x61, 0x76, 0x61, 0x22, 0x5D, 0x7D, 0x2C, 0x22, 0x65, 0x64, 0x67,
+            0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x31, 0x7D, 0x2C, 0x22, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
+            0x64, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73,
+            0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x6E, 0x6F, 0x62, 0x6F,
+            0x64, 0x79, 0x22, 0x5D, 0x7D, 0x2C, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x50, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22,
+            0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70,
+            0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x73, 0x22, 0x3A,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22,
+            0x3A, 0x35, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x73, 0x6F, 0x66, 0x74, 0x77,
+            0x61, 0x72, 0x65, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x34, 0x7D,
+            0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D,
+            0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74,
+            0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22,
+            0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32,
+            0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x35, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62,
+            0x65, 0x6C, 0x22, 0x3A, 0x22, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x22, 0x7D, 0x7D, 0x5D, 0x7D,
+            0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x54, 0x72, 0x61, 0x76, 0x65, 0x72, 0x73, 0x65, 0x72, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x7B, 0x22, 0x62, 0x75, 0x6C, 0x6B, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54,
+            0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x69, 0x64, 0x22, 0x7D, 0x2C, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70,
+            0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x7D, 0x2C, 0x22, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65,
+            0x22, 0x2C, 0x22, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x2C, 0x22, 0x6C, 0x6F, 0x70, 0x22, 0x2C, 0x22, 0x6C, 0x61,
+            0x6E, 0x67, 0x22, 0x2C, 0x22, 0x6A, 0x61, 0x76, 0x61, 0x22, 0x5D, 0x7D, 0x2C, 0x22, 0x65, 0x64, 0x67, 0x65,
+            0x43, 0x6F, 0x75, 0x6E, 0x74, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33,
+            0x7D, 0x2C, 0x22, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64,
+            0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74,
+            0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x6E, 0x6F, 0x62, 0x6F, 0x64,
+            0x79, 0x22, 0x5D, 0x7D, 0x2C, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70,
+            0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x50, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x7B, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53,
+            0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22,
+            0x3A, 0x5B, 0x5D, 0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x73, 0x22, 0x3A, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22,
+            0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x35, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61,
+            0x72, 0x65, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B,
+            0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49,
+            0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x34, 0x7D, 0x2C,
+            0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D,
+            0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65,
+            0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22,
+            0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65,
+            0x6C, 0x22, 0x3A, 0x22, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x22, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D,
+            0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x54, 0x72, 0x61, 0x76, 0x65, 0x72, 0x73, 0x65, 0x72, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x7B, 0x22, 0x62, 0x75, 0x6C, 0x6B, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x5B, 0x22, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22,
+            0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x69, 0x64, 0x22, 0x7D, 0x2C, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22,
+            0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22,
+            0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x7D, 0x2C, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x2C, 0x22,
+            0x6E, 0x61, 0x6D, 0x65, 0x22, 0x2C, 0x22, 0x6D, 0x61, 0x72, 0x6B, 0x6F, 0x22, 0x2C, 0x22, 0x61, 0x67, 0x65,
+            0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33,
+            0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x32, 0x39, 0x7D, 0x5D, 0x7D, 0x2C,
+            0x22, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70,
+            0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x22, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72,
+            0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22,
+            0x76, 0x61, 0x64, 0x61, 0x73, 0x22, 0x2C, 0x22, 0x6A, 0x6F, 0x73, 0x68, 0x22, 0x2C, 0x22, 0x6C, 0x6F, 0x70,
+            0x22, 0x5D, 0x7D, 0x2C, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65,
+            0x22, 0x3A, 0x22, 0x67, 0x3A, 0x50, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x7B, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70,
+            0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65,
+            0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x5B, 0x5D, 0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x73, 0x22, 0x3A, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22,
+            0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x35,
+            0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72,
+            0x65, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56,
+            0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22,
+            0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E,
+            0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x34, 0x7D, 0x2C, 0x22,
+            0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x2C,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78,
+            0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C,
+            0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x5D, 0x7D,
+            0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x72, 0x61,
+            0x76, 0x65, 0x72, 0x73, 0x65, 0x72, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B,
+            0x22, 0x62, 0x75, 0x6C, 0x6B, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31,
+            0x7D, 0x2C, 0x22, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x5B, 0x22, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x69, 0x64, 0x22, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x6C, 0x61, 0x62,
+            0x65, 0x6C, 0x22, 0x7D, 0x2C, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x2C, 0x22, 0x6E, 0x61, 0x6D,
+            0x65, 0x22, 0x2C, 0x22, 0x6D, 0x61, 0x72, 0x6B, 0x6F, 0x22, 0x2C, 0x22, 0x61, 0x67, 0x65, 0x22, 0x2C, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x32, 0x39, 0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x65, 0x64,
+            0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22,
+            0x3A, 0x33, 0x7D, 0x2C, 0x22, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74,
+            0x65, 0x64, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69,
+            0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x76, 0x61, 0x64,
+            0x61, 0x73, 0x22, 0x2C, 0x22, 0x6A, 0x6F, 0x73, 0x68, 0x22, 0x2C, 0x22, 0x6C, 0x6F, 0x70, 0x22, 0x5D, 0x7D,
+            0x2C, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x50, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B,
+            0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D,
+            0x5D, 0x7D, 0x2C, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56,
+            0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22,
+            0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E,
+            0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x36, 0x7D, 0x2C, 0x22,
+            0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x2C,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78,
+            0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C,
+            0x22, 0x3A, 0x22, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22,
+            0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22,
+            0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x2C,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x72, 0x61, 0x76, 0x65, 0x72,
+            0x73, 0x65, 0x72, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x62, 0x75,
+            0x6C, 0x6B, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E,
+            0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x76,
+            0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x22, 0x69, 0x64, 0x22, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22,
+            0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65,
+            0x22, 0x3A, 0x34, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54,
+            0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22,
+            0x7D, 0x2C, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x2C, 0x22, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x2C,
+            0x22, 0x6A, 0x6F, 0x73, 0x68, 0x22, 0x2C, 0x22, 0x61, 0x67, 0x65, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x32, 0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F,
+            0x75, 0x6E, 0x74, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49,
+            0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x7D, 0x2C,
+            0x22, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0x2C,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C,
+            0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x72, 0x69, 0x70, 0x70, 0x6C, 0x65, 0x22,
+            0x2C, 0x22, 0x6C, 0x6F, 0x70, 0x22, 0x5D, 0x7D, 0x2C, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x50, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x73, 0x22, 0x3A, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22,
+            0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B,
+            0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74,
+            0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74,
+            0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73,
+            0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70,
+            0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x36, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65,
+            0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22,
+            0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33,
+            0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72,
+            0x65, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56,
+            0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22,
+            0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E,
+            0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x34, 0x7D, 0x2C, 0x22,
+            0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x5D,
+            0x7D, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x54, 0x72, 0x61, 0x76, 0x65, 0x72, 0x73, 0x65, 0x72, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x62, 0x75, 0x6C, 0x6B, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70,
+            0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x22, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A,
+            0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x22, 0x69, 0x64, 0x22, 0x7D, 0x2C,
+            0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22,
+            0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x36, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x54, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22,
+            0x3A, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x7D, 0x2C, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22,
+            0x2C, 0x22, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x2C, 0x22, 0x70, 0x65, 0x74, 0x65, 0x72, 0x22, 0x2C, 0x22, 0x61,
+            0x67, 0x65, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E,
+            0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33, 0x35, 0x7D, 0x5D,
+            0x7D, 0x2C, 0x22, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74,
+            0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x22, 0x40, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x31, 0x7D, 0x2C, 0x22, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x41, 0x6E, 0x64,
+            0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A,
+            0x5B, 0x22, 0x6C, 0x6F, 0x70, 0x22, 0x5D, 0x7D, 0x2C, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x7B, 0x22,
+            0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x50, 0x61, 0x74, 0x68, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x73, 0x22, 0x3A, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x22,
+            0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A,
+            0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B,
+            0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74,
+            0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x2C, 0x7B, 0x22, 0x40,
+            0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x53, 0x65, 0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61,
+            0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74,
+            0x73, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4C, 0x69, 0x73,
+            0x74, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x7B, 0x22, 0x40, 0x74, 0x79,
+            0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76,
+            0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70,
+            0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C,
+            0x75, 0x65, 0x22, 0x3A, 0x36, 0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65,
+            0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22,
+            0x67, 0x3A, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22,
+            0x3A, 0x7B, 0x22, 0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67,
+            0x3A, 0x49, 0x6E, 0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x33,
+            0x7D, 0x2C, 0x22, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x73, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72,
+            0x65, 0x22, 0x7D, 0x7D, 0x2C, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x56,
+            0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x7B, 0x22,
+            0x69, 0x64, 0x22, 0x3A, 0x7B, 0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x49, 0x6E,
+            0x74, 0x33, 0x32, 0x22, 0x2C, 0x22, 0x40, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x36, 0x7D, 0x2C, 0x22,
+            0x6C, 0x61, 0x62, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x22, 0x7D, 0x7D, 0x5D,
+            0x7D, 0x7D, 0x7D, 0x5D, 0x7D, 0x7D, 0x7D, 0x5D, 0x7D, 0x2C, 0x22, 0x6D, 0x65, 0x74, 0x61, 0x22, 0x3A, 0x7B,
+            0x22, 0x40, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x67, 0x3A, 0x4D, 0x61, 0x70, 0x22, 0x2C, 0x22, 0x40,
+            0x76, 0x61, 0x6C, 0x75, 0x65, 0x22, 0x3A, 0x5B, 0x5D, 0x7D, 0x7D, 0x7D
+        };
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Dev/Provider/IndexTests.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Dev/Provider/IndexTests.cs
index 6d8cda2..24971b3 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Dev/Provider/IndexTests.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Dev/Provider/IndexTests.cs
@@ -23,9 +23,9 @@
 
 using System;
 using System.Collections.Generic;
+using System.Text.Json;
 using Gremlin.Net.Driver;
 using Gremlin.Net.Structure.IO.GraphSON;
-using Newtonsoft.Json.Linq;
 using Xunit;
 using Xunit.Sdk;
 
@@ -64,10 +64,10 @@
 
 internal class MyTypeReader : IGraphSONDeserializer
 {
-    public dynamic Objectify(JToken graphsonObject, GraphSONReader reader)
+    public dynamic Objectify(JsonElement graphsonObject, GraphSONReader reader)
     {
-        var x = reader.ToObject(graphsonObject["x"]);
-        var y = reader.ToObject(graphsonObject["y"]);
+        var x = reader.ToObject(graphsonObject.GetProperty("x"));
+        var y = reader.ToObject(graphsonObject.GetProperty("y"));
         return new MyType(x, y);
     }
 }
@@ -84,7 +84,7 @@
 var graphsonWriter = new GraphSON3Writer(
     new Dictionary<Type, IGraphSONSerializer> {{typeof(MyType), new MyClassWriter()}});
 
-var gremlinClient = new GremlinClient(new GremlinServer("localhost", 8182), graphsonReader, graphsonWriter);
+var gremlinClient = new GremlinClient(new GremlinServer("localhost", 8182), new GraphSON2MessageSerializer());
 // end::supportingGremlinNetIO[]
         }
     }
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs
index 61264e0..3eda74d 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs
@@ -29,6 +29,7 @@
 using Gremlin.Net.Process.Traversal;
 using Gremlin.Net.Process.Traversal.Step.Util;
 using Gremlin.Net.Process.Traversal.Strategy.Decoration;
+using Gremlin.Net.Structure.IO.GraphBinary;
 using Gremlin.Net.Structure.IO.GraphSON;
 using Xunit;
 // tag::commonImports[]
@@ -62,14 +63,21 @@
         }
         
         [Fact(Skip="No Server under localhost")]
-        public void SerializationTest()
+        public void SerializationGraphBinaryTest()
         {
-// tag::serialization[]
-var client = new GremlinClient(new GremlinServer("localhost", 8182), new GraphSON2Reader(),
-    new GraphSON2Writer(), GremlinClient.GraphSON2MimeType);
-// end::serialization[]
+// tag::serializationBinary[]
+var client = new GremlinClient(new GremlinServer("localhost", 8182), new GraphBinaryMessageSerializer());
+// end::serializationBinary[]
         }
         
+        [Fact(Skip="No Server under localhost")]
+        public void SerializationGraphson2Test()
+        {
+// tag::serializationGraphSon[]
+var client = new GremlinClient(new GremlinServer("localhost", 8182), new GraphSON2MessageSerializer());
+// end::serializationGraphSon[]
+        }
+
         [Fact(Skip="We can't apply strategies")]
         public void TraversalStrategiesTest()
         {
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Upgrade/Release35Tests.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Upgrade/Release35Tests.cs
new file mode 100644
index 0000000..659d238
--- /dev/null
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Upgrade/Release35Tests.cs
@@ -0,0 +1,43 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using Gremlin.Net.Driver;
+using Gremlin.Net.Driver.Remote;
+using Gremlin.Net.Structure.IO.GraphBinary;
+using Xunit;
+using static Gremlin.Net.Process.Traversal.AnonymousTraversalSource;
+
+namespace Gremlin.Net.IntegrationTest.Docs.Upgrade
+{
+    public class Release35Tests
+    {
+        [Fact(Skip="No Server under localhost")]
+        public void GraphBinaryTest()
+        {
+// tag::graphBinary[]
+var client = new GremlinClient(new GremlinServer("localhost", 8182), new GraphBinaryMessageSerializer());
+var g = Traversal().WithRemote(new DriverRemoteConnection(client));
+// end::graphBinary[]
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Driver/GremlinClientTests.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Driver/GremlinClientTests.cs
index e2c6ef6..3ddbeef 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Driver/GremlinClientTests.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Driver/GremlinClientTests.cs
@@ -24,12 +24,12 @@
 using System;
 using System.Collections.Generic;
 using System.Net.WebSockets;
+using System.Text.Json;
 using System.Threading.Tasks;
 using Gremlin.Net.Driver;
 using Gremlin.Net.Driver.Exceptions;
 using Gremlin.Net.Driver.Messages;
 using Gremlin.Net.IntegrationTest.Util;
-using Newtonsoft.Json.Linq;
 using Xunit;
 
 namespace Gremlin.Net.IntegrationTest.Driver
@@ -70,34 +70,6 @@
         }
 
         [Fact]
-        public async Task ShouldReturnResultWithoutDeserializingItForJTokenType()
-        {
-            var gremlinServer = new GremlinServer(TestHost, TestPort);
-            using (var gremlinClient = new GremlinClient(gremlinServer))
-            {
-                var gremlinScript = "'someString'";
-                
-                var response = await gremlinClient.SubmitWithSingleResultAsync<JToken>(gremlinScript);
-
-                //Expected:
-                /* {
-                  "@type": "g:List",
-                  "@value": [
-                    "someString"
-                  ]
-                }*/
-
-                Assert.IsType<JObject>(response);
-                Assert.Equal("g:List", response["@type"]);
-
-                var jArray = response["@value"] as JArray;
-                Assert.NotNull(jArray);
-                Assert.Equal(1, jArray.Count);
-                Assert.Equal("someString", (jArray[0] as JValue)?.Value);
-            }
-        }
-
-        [Fact]
         public async Task ShouldHandleResponseWithoutContent()
         {
             var gremlinServer = new GremlinServer(TestHost, TestPort);
@@ -129,7 +101,7 @@
                     await Assert.ThrowsAsync<ResponseException>(() => gremlinClient.SubmitAsync(requestMsg));
 
                 Assert.Equal(typeof(ResponseException), exception.GetType());
-                Assert.Contains($"ScriptEvaluationError: No such property: {requestMsg}",
+                Assert.Contains($"ServerEvaluationError: No such property: {requestMsg}",
                     exception.Message);
             }
         }
@@ -201,16 +173,14 @@
         public async Task ShouldReturnResponseAttributes()
         {
             var gremlinServer = new GremlinServer(TestHost, TestPort);
-            using (var gremlinClient = new GremlinClient(gremlinServer))
-            {
-                var requestMsg = _requestMessageProvider.GetDummyMessage();
-                var resultSet = await gremlinClient.SubmitAsync<int>(requestMsg);
+            using var gremlinClient = new GremlinClient(gremlinServer);
+            var requestMsg = _requestMessageProvider.GetDummyMessage();
+            var resultSet = await gremlinClient.SubmitAsync<int>(requestMsg);
 
-                Assert.NotNull(resultSet.StatusAttributes);
+            Assert.NotNull(resultSet.StatusAttributes);
 
-                var values= resultSet.StatusAttributes["@value"] as JArray;
-                Assert.True(values.First.ToString().Equals("host"));
-            }
+            var values = (JsonElement) resultSet.StatusAttributes["@value"];
+            Assert.True(values[0].ToString().Equals("host"));
         }
 
         [Fact]
@@ -301,7 +271,7 @@
                     await gremlinClient.SubmitAsync<int>("x");
                     Assert.True(false, "The 'x' variable should not exist after session close");
                 }
-                catch (Exception ignored)
+                catch (Exception)
                 {
                     // do nothing
                 }
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Driver/MessagesTests.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Driver/MessagesTests.cs
index 0461572..bbb107b 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Driver/MessagesTests.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Driver/MessagesTests.cs
@@ -139,7 +139,7 @@
                 var thrownException =
                     await Assert.ThrowsAsync<ResponseException>(() => gremlinClient.SubmitAsync(requestMsg));
 
-                Assert.Contains("ScriptEvaluationError", thrownException.Message);
+                Assert.Contains("ServerEvaluationError", thrownException.Message);
                 Assert.Contains(unknownLanguage, thrownException.Message);
             }
         }
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs
index 4bff42d..22f44c9 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs
@@ -26,13 +26,13 @@
 using System.Collections.Generic;
 using System.Globalization;
 using System.Linq;
+using System.Text.Json;
 using System.Text.RegularExpressions;
 using Gherkin.Ast;
 using Gremlin.Net.IntegrationTest.Gherkin.Attributes;
-using Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation;
 using Gremlin.Net.Process.Traversal;
 using Gremlin.Net.Structure;
-using Newtonsoft.Json.Linq;
+using Gremlin.Net.Structure.IO.GraphSON;
 using Xunit;
 
 using static Gremlin.Net.Process.Traversal.AnonymousTraversalSource;
@@ -46,6 +46,10 @@
         private readonly IDictionary<string, object> _parameters = new Dictionary<string, object>();
         private ITraversal _traversal;
         private object[] _result;
+        private static readonly JsonSerializerOptions JsonDeserializingOptions = new JsonSerializerOptions
+            {PropertyNamingPolicy = JsonNamingPolicy.CamelCase};
+        
+        public static ScenarioData ScenarioData { get; set; } = new ScenarioData(new GraphSON3MessageSerializer());
 
         private static readonly IDictionary<Regex, Func<string, string, object>> Parsers =
             new Dictionary<string, Func<string, string, object>>
@@ -63,7 +67,8 @@
                 {@"s\[(.*)\]", ToSet},
                 {@"m\[(.+)\]", ToMap},
                 {@"c\[(.+)\]", ToLambda},
-                {@"t\[(.+)\]", ToT}
+                {@"t\[(.+)\]", ToT},
+                {"null", (_, __) => null}
             }.ToDictionary(kv => new Regex("^" + kv.Key + "$", RegexOptions.Compiled), kv => kv.Value);
 
         private static readonly IDictionary<char, Func<string, object>> NumericParsers =
@@ -109,13 +114,16 @@
             {
                 throw new InvalidOperationException("g should be a traversal source");
             }
-            _traversal = TraversalParser.GetTraversal(traversalText, _g, _parameters);
+            
+            _traversal =
+                Gremlin.UseTraversal(ScenarioData.CurrentScenario.Name, _g, _parameters);
         }
 
         [Given("the graph initializer of")]
         public void InitTraversal(string traversalText)
         {
-            var traversal = TraversalParser.GetTraversal(traversalText, _g, _parameters);
+            var traversal =
+                Gremlin.UseTraversal(ScenarioData.CurrentScenario.Name, _g, _parameters);
             traversal.Iterate();
             
             // We may have modified the so-called `empty` graph
@@ -187,6 +195,7 @@
                     var rows = table.Rows.ToArray();
                     Assert.Equal("result", rows[0].Cells.First().Value);
                     var expected = rows.Skip(1).Select(x => ParseValue(x.Cells.First().Value, _graphName));
+
                     if (ordered)
                     {
                         Assert.Equal(expected, _result);
@@ -222,7 +231,10 @@
             {
                 traversalText = traversalText.Substring(1, traversalText.Length - 2);
             }
-            var traversal = TraversalParser.GetTraversal(traversalText, _g, _parameters);
+            
+            var traversal =
+                Gremlin.UseTraversal(ScenarioData.CurrentScenario.Name, _g, _parameters);
+            
             var count = 0;
             while (traversal.MoveNext())
             {
@@ -239,7 +251,8 @@
 
         private static object ToMap(string stringMap, string graphName)
         {
-            return ParseMapValue(JObject.Parse(stringMap), graphName);
+            var jsonMap = JsonSerializer.Deserialize<JsonElement>(stringMap, JsonDeserializingOptions);
+            return ParseMapValue(jsonMap, graphName);
         }
 
         private static object ToLambda(string stringLambda, string graphName)
@@ -263,29 +276,45 @@
                 stringNumber.Substring(0, stringNumber.Length - 1));
         }
 
-        private static object ParseMapValue(JToken value, string graphName)
+        private static object ParseMapValue(JsonElement value, string graphName)
         {
-            if (value.Type == JTokenType.Object)
+            switch (value.ValueKind)
             {
-                IDictionary<string, JToken> jsonMap = (JObject)value;
-                return jsonMap.ToDictionary(kv => ParseMapValue(kv.Key, graphName),
-                    kv => ParseMapValue(kv.Value, graphName));
+                case JsonValueKind.Object:
+                {
+                    return value.EnumerateObject().ToDictionary(property => ParseValue(property.Name, graphName),
+                        property => ParseMapValue(property.Value, graphName));
+                }
+                case JsonValueKind.Array:
+                    return value.EnumerateArray().Select(v => ParseMapValue(v, graphName)).ToArray();
+                case JsonValueKind.Number:
+                {
+                    // This can maybe be simplified when this issue is resolved:
+                    // https://github.com/dotnet/runtime/issues/31274
+                    if (value.TryGetInt32(out var integer))
+                    {
+                        return integer;
+                    }
+
+                    if (value.TryGetDouble(out var floating))
+                    {
+                        return floating;
+                    }
+
+                    throw new ArgumentOutOfRangeException(nameof(value), value, "Not a supported number type");
+                }
+                case JsonValueKind.String:
+                    return ParseValue(value.GetString(), graphName);
+                case JsonValueKind.True:
+                    return true;
+                case JsonValueKind.False:
+                    return false;
+                case JsonValueKind.Null:
+                    return null;
+                default:
+                    throw new ArgumentOutOfRangeException(nameof(value.ValueKind), value.ValueKind,
+                        "JSON type not supported");
             }
-            if (value.Type == JTokenType.Array)
-            {
-                return value.Select(v => ParseMapValue(v, graphName)).ToArray();
-            }
-            var objValue = value.ToObject<object>();
-            if (objValue is long longValue)
-            {
-                // JSON Numeric values converted to int64 by default
-                return Convert.ToInt32(longValue);
-            }
-            if (objValue is string stringValue)
-            {
-                return ParseValue(stringValue, graphName);
-            }
-            return objValue;
         }
 
         private static ISet<object> ToSet(string stringSet, string graphName)
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/GherkinTestRunner.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/GherkinTestRunner.cs
index 59fd11e..bf7624f 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/GherkinTestRunner.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/GherkinTestRunner.cs
@@ -30,7 +30,10 @@
 using Xunit;
 using Gherkin;
 using Gherkin.Ast;
+using Gremlin.Net.Driver;
 using Gremlin.Net.IntegrationTest.Gherkin.Attributes;
+using Gremlin.Net.Structure.IO.GraphBinary;
+using Gremlin.Net.Structure.IO.GraphSON;
 using Xunit.Abstractions;
 
 namespace Gremlin.Net.IntegrationTest.Gherkin
@@ -41,9 +44,27 @@
             new Dictionary<string, IgnoreReason>
             {
                 // Add here the name of scenarios to ignore and the reason, e.g.:
-                //{ "g_V_properties_propertiesXstartTimeX_drop", IgnoreReason.NoReason },
+                {"g_V_group_byXageX", IgnoreReason.NullKeysInMapNotSupported},
+
+                // expect to fix the following before 3.5.0 release. they are not failing as a result of the Gremlin
+                // itself - they are failing because of shortcomings in the test suite.
+                // https://issues.apache.org/jira/browse/TINKERPOP-2518
+                {"g_withSackX0X_V_outE_sackXsumX_byXweightX_inV_sack_sum", IgnoreReason.NoReason},
+                {"g_withSackX0X_V_repeatXoutE_sackXsumX_byXweightX_inVX_timesX2X_sack", IgnoreReason.NoReason},
+                {
+                    "g_withBulkXfalseX_withSackX1_sumX_VX1X_localXoutEXknowsX_barrierXnormSackX_inVX_inXknowsX_barrier_sack",
+                    IgnoreReason.NoReason
+                },
+                {
+                    "g_withSackX1_sumX_VX1X_localXoutXknowsX_barrierXnormSackXX_inXknowsX_barrier_sack",
+                    IgnoreReason.NoReason
+                },
+                {
+                    "g_V_hasXperson_name_markoX_bothXknowsX_groupCount_byXvaluesXnameX_foldX",
+                    IgnoreReason.ArrayKeysInMapNotAssertingInGherkin
+                },
             };
-        
+
         private static class Keywords
         {
             public const string Given = "GIVEN";
@@ -59,14 +80,14 @@
             When,
             Then
         }
-        
+
         private static readonly IDictionary<StepBlock, Type> Attributes = new Dictionary<StepBlock, Type>
         {
-            { StepBlock.Given, typeof(GivenAttribute) },
-            { StepBlock.When, typeof(WhenAttribute) },
-            { StepBlock.Then, typeof(ThenAttribute) }
+            {StepBlock.Given, typeof(GivenAttribute)},
+            {StepBlock.When, typeof(WhenAttribute)},
+            {StepBlock.Then, typeof(ThenAttribute)}
         };
-        
+
         private readonly ITestOutputHelper _output;
 
         public GherkinTestRunner(ITestOutputHelper output)
@@ -74,12 +95,16 @@
             _output = output;
         }
 
-        [Fact]
-        public void RunGherkinBasedTests()
+        [Theory]
+        [MemberData(nameof(MessageSerializers))]
+        public void RunGherkinBasedTests(IMessageSerializer messageSerializer)
         {
-            WriteOutput("Starting Gherkin-based tests");
+            WriteOutput($"Starting Gherkin-based tests with serializer: {messageSerializer.GetType().Name}");
+            Gremlin.InstantiateTranslationsForTestRun();
             var stepDefinitionTypes = GetStepDefinitionTypes();
             var results = new List<ResultFeature>();
+            using var scenarioData = new ScenarioData(messageSerializer);
+            CommonSteps.ScenarioData = scenarioData;
             foreach (var feature in GetFeatures())
             {
                 var resultFeature = new ResultFeature(feature);
@@ -93,6 +118,7 @@
                         failedSteps.Add(scenario.Steps.First(), new IgnoreException(reason));
                         continue;
                     }
+
                     StepBlock? currentStep = null;
                     StepDefinition stepDefinition = null;
                     foreach (var step in scenario.Steps)
@@ -101,14 +127,16 @@
                         currentStep = GetStepBlock(currentStep, step.Keyword);
                         if (currentStep == StepBlock.Given && previousStep != StepBlock.Given)
                         {
-                            stepDefinition?.Dispose();
                             stepDefinition = GetStepDefinitionInstance(stepDefinitionTypes, step.Text);
                         }
+
                         if (stepDefinition == null)
                         {
                             throw new NotSupportedException(
                                 $"Step '{step.Text} not supported without a 'Given' step first");
                         }
+
+                        scenarioData.CurrentScenario = scenario;
                         var result = ExecuteStep(stepDefinition, currentStep.Value, step);
                         if (result != null)
                         {
@@ -119,11 +147,18 @@
                     }
                 }
             }
+
             OutputResults(results);
-            WriteOutput("Finished Gherkin-based tests");
-            ScenarioData.Shutdown();
+            WriteOutput($"Finished Gherkin-based tests with serializer: {messageSerializer.GetType().Name}.");
         }
 
+        public static IEnumerable<object[]> MessageSerializers =>
+            new List<object[]>
+            {
+                new object[] {new GraphBinaryMessageSerializer()},
+                new object[] {new GraphSON3MessageSerializer()}
+            };
+
         private void WriteOutput(string line)
         {
 #if DEBUG
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
new file mode 100644
index 0000000..4df8e1d
--- /dev/null
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -0,0 +1,704 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+
+
+//********************************************************************************
+//* Do NOT edit this file directly - generated by build/generate.groovy
+//********************************************************************************
+
+
+using System;
+using System.Collections.Generic;
+using Gremlin.Net.Structure;
+using Gremlin.Net.Process.Traversal;
+using Gremlin.Net.Process.Traversal.Strategy.Decoration;
+
+namespace Gremlin.Net.IntegrationTest.Gherkin
+{
+    public class Gremlin
+    {
+        public static void InstantiateTranslationsForTestRun()
+        {
+            // We need to copy the fixed translations as we remove translations from the list after using them
+            // so we can enumerate through the translations while evaluating a scenario.
+            _translationsForTestRun =
+                new Dictionary<string, List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>>(
+                    FixedTranslations.Count);
+            foreach (var (traversal, translations) in FixedTranslations)
+            {
+                _translationsForTestRun.Add(traversal,
+                    new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>(translations));
+            }
+        }
+
+        private static IDictionary<string, List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>>
+            _translationsForTestRun;
+
+        private static readonly IDictionary<string, List<Func<GraphTraversalSource, IDictionary<string, object>,ITraversal>>> FixedTranslations = 
+            new Dictionary<string, List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>>
+            {
+               {"g_V_branchXlabel_eq_person__a_bX_optionXa__ageX_optionXb__langX_optionXb__nameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Branch<object>((IFunction) p["l1"]).Option("a",__.Values<object>("age")).Option("b",__.Values<object>("lang")).Option("b",__.Values<object>("name"))}}, 
+               {"g_V_branchXlabel_isXpersonX_countX_optionX1__ageX_optionX0__langX_optionX0__nameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Branch<object>(__.Label().Is("person").Count()).Option(p["xx1"],__.Values<object>("age")).Option(p["xx2"],__.Values<object>("lang")).Option(p["xx2"],__.Values<object>("name"))}}, 
+               {"g_V_branchXlabel_isXpersonX_countX_optionX1__ageX_optionX0__langX_optionX0__nameX_optionXany__labelX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Branch<object>(__.Label().Is("person").Count()).Option(p["xx1"],__.Values<object>("age")).Option(p["xx2"],__.Values<object>("lang")).Option(p["xx2"],__.Values<object>("name")).Option(Pick.Any,__.Label())}}, 
+               {"g_V_branchXageX_optionXltX30X__youngX_optionXgtX30X__oldX_optionXnone__on_the_edgeX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Branch<object>(__.Values<object>("age")).Option(P.Lt(30),__.Constant<object>("young")).Option(P.Gt(30),__.Constant<object>("old")).Option(Pick.None,__.Constant<object>("on the edge"))}}, 
+               {"g_V_branchXidentityX_optionXhasLabelXsoftwareX__inXcreatedX_name_order_foldX_optionXhasXname_vadasX__ageX_optionXneqX123X__bothE_countX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Branch<object>(__.Identity()).Option(__.HasLabel("software"),__.In("created").Values<object>("name").Order().Fold()).Option(__.Has("name","vadas"),__.Values<object>("age")).Option(P.Neq(123),__.BothE().Count())}}, 
+               {"g_V_chooseXout_countX_optionX2L_nameX_optionX3L_ageX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.Out().Count()).Option(p["xx1"],__.Values<object>("name")).Option(p["xx2"],__.Values<object>("age"))}}, 
+               {"g_V_chooseXlabel_eqXpersonX__outXknowsX__inXcreatedXX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>((IPredicate) p["pred1"],__.Out("knows"),__.In("created")).Values<object>("name")}}, 
+               {"g_V_chooseXhasLabelXpersonX_and_outXcreatedX__outXknowsX__identityX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.HasLabel("person").And().Out("created"),__.Out("knows"),__.Identity()).Values<object>("name")}}, 
+               {"g_V_chooseXlabelX_optionXblah__outXknowsXX_optionXbleep__outXcreatedXX_optionXnone__identityX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.Label()).Option("blah",__.Out("knows")).Option("bleep",__.Out("created")).Option(Pick.None,__.Identity()).Values<object>("name")}}, 
+               {"g_V_chooseXoutXknowsX_count_isXgtX0XX__outXknowsXX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.Out("knows").Count().Is(P.Gt(0)),__.Out("knows")).Values<object>("name")}}, 
+               {"g_V_hasLabelXpersonX_asXp1X_chooseXoutEXknowsX__outXknowsXX_asXp2X_selectXp1_p2X_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").As("p1").Choose<object>(__.OutE("knows"),__.Out("knows")).As("p2").Select<object>("p1","p2").By("name")}}, 
+               {"g_V_hasLabelXpersonX_chooseXageX__optionX27L__constantXyoungXX_optionXnone__constantXoldXX_groupCount", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Choose<object>(__.Values<object>("age")).Option(p["xx1"],__.Constant<object>("young")).Option(Pick.None,__.Constant<object>("old")).GroupCount<object>()}}, 
+               {"g_injectX1X_chooseXisX1X__constantX10Xfold__foldX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(p["xx2"]).Choose<object>(__.Is(p["xx2"]),__.Constant<object>(p["xx1"]).Fold(),__.Fold<object>())}}, 
+               {"g_injectX2X_chooseXisX1X__constantX10Xfold__foldX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(p["xx3"]).Choose<object>(__.Is(p["xx2"]),__.Constant<object>(p["xx1"]).Fold(),__.Fold<object>())}}, 
+               {"g_V_localXpropertiesXlocationX_order_byXvalueX_limitX2XX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Local<object>(__.Properties<object>("location").Order().By(T.Value,Order.Asc).Range<object>(0,2)).Value<object>()}}, 
+               {"g_V_hasXlabel_personX_asXaX_localXoutXcreatedX_asXbXX_selectXa_bX_byXnameX_byXidX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has(T.Label,"person").As("a").Local<object>(__.Out("created").As("b")).Select<object>("a","b").By("name").By(T.Id)}}, 
+               {"g_V_localXoutE_countX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Local<object>(__.OutE().Count())}}, 
+               {"g_VX1X_localXoutEXknowsX_limitX1XX_inV_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Local<object>(__.OutE("knows").Limit<object>(1)).InV().Values<object>("name")}}, 
+               {"g_V_localXbothEXcreatedX_limitX1XX_otherV_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Local<object>(__.BothE("created").Limit<object>(1)).OtherV().Values<object>("name")}}, 
+               {"g_VX4X_localXbothEX1_createdX_limitX1XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid4"]).Local<object>(__.BothE("created").Limit<object>(1))}}, 
+               {"g_VX4X_localXbothEXknows_createdX_limitX1XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid4"]).Local<object>(__.BothE("knows","created").Limit<object>(1))}}, 
+               {"g_VX4X_localXbothE_limitX1XX_otherV_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid4"]).Local<object>(__.BothE().Limit<object>(1)).OtherV().Values<object>("name")}}, 
+               {"g_VX4X_localXbothE_limitX2XX_otherV_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid4"]).Local<object>(__.BothE().Limit<object>(2)).OtherV().Values<object>("name")}}, 
+               {"g_V_localXinEXknowsX_limitX2XX_outV_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Local<object>(__.InE("knows").Limit<object>(2)).OutV().Values<object>("name")}}, 
+               {"g_V_localXmatchXproject__created_person__person_name_nameX_selectXname_projectX_by_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Local<object>(__.Match<object>(__.As("project").In("created").As("person"),__.As("person").Values<object>("name").As("name"))).Select<object>("name","project").By().By("name")}}, 
+               {"g_VX2X_optionalXoutXknowsXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid2"]).Optional<object>(__.Out("knows"))}}, 
+               {"g_VX2X_optionalXinXknowsXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid2"]).Optional<object>(__.In("knows"))}}, 
+               {"g_V_hasLabelXpersonX_optionalXoutXknowsX_optionalXoutXcreatedXXX_path", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Optional<object>(__.Out("knows").Optional<object>(__.Out("created"))).Path()}}, 
+               {"g_V_optionalXout_optionalXoutXX_path", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Optional<object>(__.Out().Optional<object>(__.Out())).Path()}}, 
+               {"g_VX1X_optionalXaddVXdogXX_label", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").AddV("software").Property(T.Id,5).Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property(T.Id,6).Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property(T.Id,7).Property("weight",0.5).AddE("knows").From("marko").To("josh").Property(T.Id,8).Property("weight",1.0).AddE("created").From("marko").To("lop").Property(T.Id,9).Property("weight",0.4).AddE("created").From("josh").To("ripple").Property(T.Id,10).Property("weight",1.0).AddE("created").From("josh").To("lop").Property(T.Id,11).Property("weight",0.4).AddE("created").From("peter").To("lop").Property(T.Id,12).Property("weight",0.2), (g,p) =>g.V(p["vid1"]).Optional<object>(__.AddV("dog")).Label(), (g,p) =>g.V()}}, 
+               {"g_V_repeatXoutX_timesX2X_emit_path", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Repeat(__.Out()).Times(2).Emit().Path()}}, 
+               {"g_V_repeatXoutX_timesX2X_repeatXinX_timesX2X_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Repeat(__.Out()).Times(2).Repeat(__.In()).Times(2).Values<object>("name")}}, 
+               {"g_V_repeatXoutX_timesX2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Repeat(__.Out()).Times(2)}}, 
+               {"g_V_repeatXoutX_timesX2X_emit", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Repeat(__.Out()).Times(2).Emit()}}, 
+               {"g_VX1X_timesX2X_repeatXoutX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Times(2).Repeat(__.Out()).Values<object>("name")}}, 
+               {"g_V_emit_timesX2X_repeatXoutX_path", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Emit().Times(2).Repeat(__.Out()).Path()}}, 
+               {"g_V_emit_repeatXoutX_timesX2X_path", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Emit().Repeat(__.Out()).Times(2).Path()}}, 
+               {"g_VX1X_emitXhasXlabel_personXX_repeatXoutX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Emit(__.Has(T.Label,"person")).Repeat(__.Out()).Values<object>("name")}}, 
+               {"g_V_repeatXgroupCountXmX_byXnameX_outX_timesX2X_capXmX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Repeat(__.GroupCount("m").By("name").Out()).Times(2).Cap<object>("m")}}, 
+               {"g_VX1X_repeatXgroupCountXmX_byXloopsX_outX_timesX3X_capXmX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Repeat(__.GroupCount("m").By(__.Loops()).Out()).Times(3).Cap<object>("m")}}, 
+               {"g_V_repeatXbothX_timesX10X_asXaX_out_asXbX_selectXa_bX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Repeat(__.Both()).Times(10).As("a").Out().As("b").Select<object>("a","b").Count()}}, 
+               {"g_VX1X_repeatXoutX_untilXoutE_count_isX0XX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Repeat(__.Out()).Until(__.OutE().Count().Is(0)).Values<object>("name")}}, 
+               {"g_V_repeatXbothX_untilXname_eq_marko_or_loops_gt_1X_groupCount_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Repeat(__.Both()).Until((IPredicate) p["pred1"]).GroupCount<object>().By("name")}}, 
+               {"g_V_hasXname_markoX_repeatXoutE_inV_simplePathX_untilXhasXname_rippleXX_path_byXnameX_byXlabelX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name","marko").Repeat(__.OutE().InV().SimplePath()).Until(__.Has("name","ripple")).Path().By("name").By(T.Label)}}, 
+               {"g_V_hasXloop_name_loopX_repeatXinX_timesX5X_path_by_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("loops","name","loop").Repeat(__.In()).Times(5).Path().By("name")}}, 
+               {"g_V_repeatXout_repeatXoutX_timesX1XX_timesX1X_limitX1X_path_by_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Repeat(__.Out().Repeat(__.Out()).Times(1)).Times(1).Limit<object>(1).Path().By("name")}}, 
+               {"g_V_repeatXoutXknowsXX_untilXrepeatXoutXcreatedXX_emitXhasXname_lopXXX_path_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Repeat(__.Out("knows")).Until(__.Repeat(__.Out("created")).Emit(__.Has("name","lop"))).Path().By("name")}}, 
+               {"g_V_repeatXrepeatXout_createdXX_untilXhasXname_rippleXXXemit_lang", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Repeat(__.Repeat(__.Out("created")).Until(__.Has("name","ripple"))).Emit().Values<object>("lang")}}, 
+               {"g_V_untilXconstantXtrueXX_repeatXrepeatXout_createdXX_untilXhasXname_rippleXXXemit_lang", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Until(__.Constant<object>(true)).Repeat(__.Repeat(__.Out("created")).Until(__.Has("name","ripple"))).Emit().Values<object>("lang")}}, 
+               {"g_V_emit_repeatXa_outXknows_filterXloops_isX0XX_lang", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Emit().Repeat("a",__.Out("knows").Filter(__.Loops("a").Is(0))).Values<object>("lang")}}, 
+               {"g_VX3X_repeatXbothX_createdXX_untilXloops_is_40XXemit_repeatXin_knowsXX_emit_loopsXisX1Xdedup_values", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid3"]).Repeat(__.Both("created")).Until(__.Loops().Is(40)).Emit(__.Repeat(__.In("knows")).Emit(__.Loops().Is(1))).Dedup().Values<object>("name")}}, 
+               {"g_VX1X_repeatXrepeatXunionXout_uses_out_traversesXX_whereXloops_isX0X_timesX1X_timeX2X_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Repeat(__.Repeat(__.Union<object>(__.Out("uses"),__.Out("traverses")).Where(__.Loops().Is(0))).Times(1)).Times(2).Values<object>("name")}}, 
+               {"g_V_repeatXa_outXknows_repeatXb_outXcreatedX_filterXloops_isX0XX_emit_lang", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Repeat("a",__.Out("knows").Repeat("b",__.Out("created").Filter(__.Loops("a").Is(0))).Emit()).Emit().Values<object>("lang")}}, 
+               {"g_VX6X_repeatXa_bothXcreatedX_simplePathX_emitXrepeatXb_bothXknowsXX_untilXloopsXbX_asXb_whereXloopsXaX_asXbX_hasXname_vadasXX_dedup_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid6"]).Repeat("a",__.Both("created").SimplePath()).Emit(__.Repeat("b",__.Both("knows")).Until(__.Loops("b").As("b").Where(__.Loops("a").As("b"))).Has("name","vadas")).Dedup().Values<object>("name")}}, 
+               {"g_V_unionXout__inX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Union<object>(__.Out(),__.In()).Values<object>("name")}}, 
+               {"g_VX1X_unionXrepeatXoutX_timesX2X__outX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Union<object>(__.Repeat(__.Out()).Times(2),__.Out()).Values<object>("name")}}, 
+               {"g_V_chooseXlabel_is_person__unionX__out_lang__out_nameX__in_labelX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.Label().Is("person"),__.Union<object>(__.Out().Values<object>("lang"),__.Out().Values<object>("name")),__.In().Label())}}, 
+               {"g_V_chooseXlabel_is_person__unionX__out_lang__out_nameX__in_labelX_groupCount", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.Label().Is("person"),__.Union<object>(__.Out().Values<object>("lang"),__.Out().Values<object>("name")),__.In().Label()).GroupCount<object>()}}, 
+               {"g_V_unionXrepeatXunionXoutXcreatedX__inXcreatedXX_timesX2X__repeatXunionXinXcreatedX__outXcreatedXX_timesX2XX_label_groupCount", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Union<object>(__.Repeat(__.Union<object>(__.Out("created"),__.In("created"))).Times(2),__.Repeat(__.Union<object>(__.In("created"),__.Out("created"))).Times(2)).Label().GroupCount<object>()}}, 
+               {"g_VX1_2X_unionXoutE_count__inE_count__outE_weight_sumX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"],p["vid2"]).Union<object>(__.OutE().Count(),__.InE().Count(),__.OutE().Values<object>("weight").Sum<object>())}}, 
+               {"g_VX1_2X_localXunionXoutE_count__inE_count__outE_weight_sumXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"],p["vid2"]).Local<object>(__.Union<object>(__.OutE().Count(),__.InE().Count(),__.OutE().Values<object>("weight").Sum<object>()))}}, 
+               {"g_VX1_2X_localXunionXcountXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"],p["vid2"]).Local<object>(__.Union<object>(__.Count()))}}, 
+               {"g_V_andXhasXage_gt_27X__outE_count_gte_2X_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().And(__.Has("age",P.Gt(27)),__.OutE().Count().Is(P.Gte(2))).Values<object>("name")}}, 
+               {"g_V_andXoutE__hasXlabel_personX_and_hasXage_gte_32XX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().And(__.OutE(),__.Has(T.Label,"person").And().Has("age",P.Gte(32))).Values<object>("name")}}, 
+               {"g_V_asXaX_outXknowsX_and_outXcreatedX_inXcreatedX_asXaX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out("knows").And().Out("created").In("created").As("a").Values<object>("name")}}, 
+               {"g_V_asXaX_andXselectXaX_selectXaXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").And(__.Select<object>("a"),__.Select<object>("a"))}}, 
+               {"g_V_hasXname_markoX_and_hasXname_markoX_and_hasXname_markoX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name","marko").And().Has("name","marko").And().Has("name","marko")}}, 
+               {"g_V_coinX1X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Coin(1.0)}}, 
+               {"g_V_coinX0X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Coin(0.0)}}, 
+               {"g_VX1X_outXcreatedX_inXcreatedX_cyclicPath", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out("created").In("created").CyclicPath()}}, 
+               {"g_VX1X_outXcreatedX_inXcreatedX_cyclicPath_path", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out("created").In("created").CyclicPath().Path()}}, 
+               {"g_VX1X_asXaX_outXcreatedX_asXbX_inXcreatedX_asXcX_cyclicPath_fromXaX_toXbX_path", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).As("a").Out("created").As("b").In("created").As("c").CyclicPath().From("a").To("b").Path()}}, 
+               {"g_V_out_in_valuesXnameX_fold_dedupXlocalX_unfold", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Out().In().Values<object>("name").Fold().Dedup(Scope.Local).Unfold<object>()}}, 
+               {"g_V_out_asXxX_in_asXyX_selectXx_yX_byXnameX_fold_dedupXlocal_x_yX_unfold", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Out().As("x").In().As("y").Select<object>("x","y").By("name").Fold().Dedup(Scope.Local,"x","y").Unfold<object>()}}, 
+               {"g_V_both_dedup_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Both().Dedup().Values<object>("name")}}, 
+               {"g_V_both_hasXlabel_softwareX_dedup_byXlangX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Both().Has(T.Label,"software").Dedup().By("lang").Values<object>("name")}}, 
+               {"g_V_both_name_order_byXa_bX_dedup_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Both().Properties<object>("name").Order().By((IComparator) p["c1"]).Dedup().Value<object>()}}, 
+               {"g_V_both_both_name_dedup", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Both().Both().Values<object>("name").Dedup()}}, 
+               {"g_V_both_both_dedup", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Both().Both().Dedup()}}, 
+               {"g_V_both_both_dedup_byXlabelX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Both().Both().Dedup().By(T.Label)}}, 
+               {"g_V_group_byXlabelX_byXbothE_weight_dedup_foldX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Group<object,object>().By(T.Label).By(__.BothE().Values<object>("weight").Dedup().Fold())}}, 
+               {"g_V_asXaX_both_asXbX_dedupXa_bX_byXlabelX_selectXa_bX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Both().As("b").Dedup("a","b").By(T.Label).Select<object>("a","b")}}, 
+               {"g_V_asXaX_outXcreatedX_asXbX_inXcreatedX_asXcX_dedupXa_bX_path", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out("created").As("b").In("created").As("c").Dedup("a","b").Path()}}, 
+               {"g_V_outE_asXeX_inV_asXvX_selectXeX_order_byXweight_ascX_selectXvX_valuesXnameX_dedup", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().OutE().As("e").InV().As("v").Select<object>("e").Order().By("weight",Order.Asc).Select<object>("v").Values<object>("name").Dedup()}}, 
+               {"g_V_both_both_dedup_byXoutE_countX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Both().Both().Dedup().By(__.OutE().Count()).Values<object>("name")}}, 
+               {"g_V_groupCount_selectXvaluesX_unfold_dedup", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().GroupCount<object>().Select<object>(Column.Values).Unfold<object>().Dedup()}}, 
+               {"g_V_asXaX_repeatXbothX_timesX3X_emit_name_asXbX_group_byXselectXaXX_byXselectXbX_dedup_order_foldX_selectXvaluesX_unfold_dedup", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Repeat(__.Both()).Times(3).Emit().Values<object>("name").As("b").Group<object,object>().By(__.Select<object>("a")).By(__.Select<object>("b").Dedup().Order().Fold()).Select<object>(Column.Values).Unfold<object>().Dedup()}}, 
+               {"g_V_repeatXdedupX_timesX2X_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Repeat(__.Dedup()).Times(2).Count()}}, 
+               {"g_V_both_group_by_byXout_dedup_foldX_unfold_selectXvaluesX_unfold_out_order_byXnameX_limitX1X_valuesXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Both().Group<object,object>().By().By(__.Out().Dedup().Fold()).Unfold<object>().Select<object>(Column.Values).Unfold<object>().Out().Order().By("name").Limit<object>(1).Values<object>("name")}}, 
+               {"g_V_bothE_properties_dedup_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().BothE().Properties<object>().Dedup().Count()}}, 
+               {"g_V_both_properties_dedup_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Both().Properties<object>().Dedup().Count()}}, 
+               {"g_V_both_properties_properties_dedup_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Both().Properties<object>().Properties<object>().Dedup().Count()}}, 
+               {"g_V_drop", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV().As("a").AddV().As("b").AddE("knows").To("a"), (g,p) =>g.V().Drop(), (g,p) =>g.V(), (g,p) =>g.E()}}, 
+               {"g_V_outE_drop", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV().As("a").AddV().As("b").AddE("knows").To("a"), (g,p) =>g.V().OutE().Drop(), (g,p) =>g.V(), (g,p) =>g.E()}}, 
+               {"g_V_properties_drop", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV().Property("name","bob").AddV().Property("name","alice"), (g,p) =>g.V().Properties<object>().Drop(), (g,p) =>g.V(), (g,p) =>g.V().Properties<object>()}}, 
+               {"g_E_propertiesXweightX_drop", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").AddV("software").Property(T.Id,5).Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property(T.Id,6).Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property(T.Id,7).Property("weight",0.5).AddE("knows").From("marko").To("josh").Property(T.Id,8).Property("weight",1.0).AddE("created").From("marko").To("lop").Property(T.Id,9).Property("weight",0.4).AddE("created").From("josh").To("ripple").Property(T.Id,10).Property("weight",1.0).AddE("created").From("josh").To("lop").Property(T.Id,11).Property("weight",0.4).AddE("created").From("peter").To("lop").Property(T.Id,12).Property("weight",0.2), (g,p) =>g.E().Properties<object>("weight").Drop(), (g,p) =>g.E().Properties<object>()}}, 
+               {"g_V_properties_propertiesXstartTimeX_drop", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV().Property("name","bob").Property(Cardinality.List,"location","ny","startTime",2014,"endTime",2016).Property(Cardinality.List,"location","va","startTime",2016).AddV().Property("name","alice").Property(Cardinality.List,"location","va","startTime",2014,"endTime",2016).Property(Cardinality.List,"location","ny","startTime",2016), (g,p) =>g.V().Properties<object>().Properties<object>("startTime").Drop(), (g,p) =>g.V().Properties<object>().Properties<object>(), (g,p) =>g.V().Properties<object>().Properties<object>("startTime")}}, 
+               {"g_V_filterXfalseX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Filter((IPredicate) p["pred1"])}}, 
+               {"g_V_filterXtrueX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Filter((IPredicate) p["pred1"])}}, 
+               {"g_V_filterXlang_eq_javaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Filter((IPredicate) p["pred1"])}}, 
+               {"g_VX1X_filterXage_gt_30X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Filter((IPredicate) p["pred1"])}}, 
+               {"g_VX2X_filterXage_gt_30X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid2"]).Filter((IPredicate) p["pred1"])}}, 
+               {"g_VX1X_out_filterXage_gt_30X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out().Filter((IPredicate) p["pred1"])}}, 
+               {"g_V_filterXname_startsWith_m_OR_name_startsWith_pX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Filter((IPredicate) p["pred1"])}}, 
+               {"g_E_filterXfalseX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E().Filter((IPredicate) p["pred1"])}}, 
+               {"g_E_filterXtrueX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E().Filter((IPredicate) p["pred1"])}}, 
+               {"g_V_outXcreatedX_hasXname__mapXlengthX_isXgtX3XXX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Out("created").Has("name",__.Map<object>((IFunction) p["l1"]).Is(P.Gt(3))).Values<object>("name")}}, 
+               {"g_VX1X_hasXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Has("name")}}, 
+               {"g_VX1X_hasXcircumferenceX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Has("circumference")}}, 
+               {"g_VX1X_hasXname_markoX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Has("name","marko")}}, 
+               {"g_VX2X_hasXname_markoX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Has("name","marko")}}, 
+               {"g_V_hasXname_markoX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name","marko")}}, 
+               {"g_V_hasXname_blahX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name","blah")}}, 
+               {"g_V_hasXage_gt_30X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age",P.Gt(30))}}, 
+               {"g_V_hasXage_isXgt_30XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age",__.Is(P.Gt(30)))}}, 
+               {"g_V_hasXlabel_isXsoftwareXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has(T.Label,__.Is("software"))}}, 
+               {"g_VX1X_hasXage_gt_30X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Has("age",P.Gt(30))}}, 
+               {"g_VX4X_hasXage_gt_30X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid4"]).Has("age",P.Gt(30))}}, 
+               {"g_VXv1X_hasXage_gt_30X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V((Vertex) p["v1"]).Has("age",P.Gt(30))}}, 
+               {"g_VXv4X_hasXage_gt_30X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V((Vertex) p["v4"]).Has("age",P.Gt(30))}}, 
+               {"g_VX1X_out_hasXid_lt_3X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out().Has(T.Id,p["xx1"])}}, 
+               {"g_VX1AsStringX_out_hasXid_2AsStringX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out().HasId(p["vid2"])}}, 
+               {"g_VX1X_out_hasXid_2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V((Vertex) p["v2"]).Has("age",P.Gt(30))}}, 
+               {"g_VX1X_out_hasIdX2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out().HasId(p["vid2"])}}, 
+               {"g_VX1X_out_hasXid_2_3X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out().HasId(p["vid2"],p["vid3"])}}, 
+               {"g_VX1X_out_hasXid_2AsString_3AsStringX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out().HasId(p["vid2"],p["vid3"])}}, 
+               {"g_V_hasXblahX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("blah")}}, 
+               {"g_EX7X_hasXlabelXknowsX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E(p["eid7"]).HasLabel("knows")}}, 
+               {"g_E_hasXlabelXknowsX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E().HasLabel("knows")}}, 
+               {"g_E_hasLabelXuses_traversesX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E().HasLabel("uses","traverses")}}, 
+               {"g_V_hasLabelXperson_software_blahX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person","software","blah")}}, 
+               {"g_V_hasXperson_name_markoX_age", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("person","name","marko").Values<object>("age")}}, 
+               {"g_VX1X_outE_hasXweight_inside_0_06X_inV", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).OutE().Has("weight",P.Gt(0.0).And(P.Lt(0.6))).InV()}}, 
+               {"g_EX11X_outV_outE_hasXid_10X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E(p["eid11"]).OutV().OutE().Has(T.Id,p["eid10"])}}, 
+               {"g_EX11X_outV_outE_hasXid_10AsStringX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E(p["eid11"]).OutV().OutE().Has(T.Id,p["eid10"])}}, 
+               {"g_V_hasXlocationX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("location")}}, 
+               {"g_V_hasLabelXpersonX_hasXage_notXlteX10X_andXnotXbetweenX11_20XXXX_andXltX29X_orXeqX35XXXX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Has("age",P.Gt(10).Or(P.Gte(11).And(P.Lt(20))).And(P.Lt(29).Or(P.Eq(35)))).Values<object>("name")}}, 
+               {"g_V_in_hasIdXneqX1XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().In().HasId(p["xx1"])}}, 
+               {"g_V_hasXage_withinX27X_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age",P.Within(new List<object> {27})).Count()}}, 
+               {"g_V_hasXage_withinX27_29X_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age",P.Within(new List<object> {27, 29})).Count()}}, 
+               {"g_V_hasXage_withoutX27X_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age",P.Without(new List<object> {27})).Count()}}, 
+               {"g_V_hasXage_withoutX27_29X_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age",P.Without(new List<object> {27, 29})).Count()}}, 
+               {"g_V_both_dedup_properties_hasKeyXageX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Both().Properties<object>().Dedup().HasKey("age").Value<object>()}}, 
+               {"g_V_both_dedup_properties_hasKeyXageX_hasValueXgtX30XX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Both().Properties<object>().Dedup().HasKey("age").HasValue(P.Gt(30)).Value<object>()}}, 
+               {"g_V_bothE_properties_dedup_hasKeyXweightX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().BothE().Properties<object>().Dedup().HasKey("weight").Value<object>()}}, 
+               {"g_V_bothE_properties_dedup_hasKeyXweightX_hasValueXltX0d3XX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().BothE().Properties<object>().Dedup().HasKey("weight").HasValue(P.Lt(0.3)).Value<object>()}}, 
+               {"g_V_hasNotXageX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasNot("age").Values<object>("name")}}, 
+               {"g_V_hasIdX1X_hasIdX2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasId(p["vid1"]).HasId(p["vid2"])}}, 
+               {"g_V_hasLabelXpersonX_hasLabelXsoftwareX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").HasLabel("software")}}, 
+               {"g_V_hasIdXemptyX_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasId(p["xx1"]).Count()}}, 
+               {"g_V_hasIdXwithinXemptyXX_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasId(p["xx1"]).Count()}}, 
+               {"g_V_hasIdXwithoutXemptyXX_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasId(p["xx1"]).Count()}}, 
+               {"g_V_notXhasIdXwithinXemptyXXX_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Not(__.HasId(p["xx1"])).Count()}}, 
+               {"g_V_hasXname_containingXarkXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name",TextP.Containing("ark"))}}, 
+               {"g_V_hasXname_startingWithXmarXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name",TextP.StartingWith("mar"))}}, 
+               {"g_V_hasXname_endingWithXasXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name",TextP.EndingWith("as"))}}, 
+               {"g_V_hasXperson_name_containingXoX_andXltXmXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("person","name",TextP.Containing("o").And(P.Lt("m")))}}, 
+               {"g_V_hasXname_gtXmX_andXcontainingXoXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name",P.Gt("m").And(TextP.Containing("o")))}}, 
+               {"g_V_hasXname_not_containingXarkXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name",TextP.NotContaining("ark"))}}, 
+               {"g_V_hasXname_not_startingWithXmarXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name",TextP.NotStartingWith("mar"))}}, 
+               {"g_V_hasXname_not_endingWithXasXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name",TextP.NotEndingWith("as"))}}, 
+               {"g_V_hasXp_neqXvXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("p",P.Neq("v"))}}, 
+               {"g_V_hasXage_gtX18X_andXltX30XXorXgtx35XXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age",P.Gt(18).And(P.Lt(30)).Or(P.Gt(35)))}}, 
+               {"g_V_hasXage_gtX18X_andXltX30XXorXltx35XXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age",P.Gt(18).And(P.Lt(30)).And(P.Lt(35)))}}, 
+               {"g_V_valuesXageX_isX32X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Is(32)}}, 
+               {"g_V_valuesXageX_isXlte_30X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Is(P.Lte(30))}}, 
+               {"g_V_valuesXageX_isXgte_29X_isXlt_34X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Is(P.Gte(29)).Is(P.Lt(34))}}, 
+               {"g_V_whereXinXcreatedX_count_isX1XX_valuesXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Where(__.In("created").Count().Is(1)).Values<object>("name")}}, 
+               {"g_V_whereXinXcreatedX_count_isXgte_2XX_valuesXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Where(__.In("created").Count().Is(P.Gte(2))).Values<object>("name")}}, 
+               {"g_V_orXhasXage_gt_27X__outE_count_gte_2X_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Or(__.Has("age",P.Gt(27)),__.OutE().Count().Is(P.Gte(2))).Values<object>("name")}}, 
+               {"g_V_orXoutEXknowsX__hasXlabel_softwareX_or_hasXage_gte_35XX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Or(__.OutE("knows"),__.Has(T.Label,"software").Or().Has("age",P.Gte(35))).Values<object>("name")}}, 
+               {"g_V_asXaX_orXselectXaX_selectXaXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Or(__.Select<object>("a"),__.Select<object>("a"))}}, 
+               {"g_VX1X_out_limitX2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out().Limit<object>(2)}}, 
+               {"g_V_localXoutE_limitX1X_inVX_limitX3X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Local<object>(__.OutE().Limit<object>(1)).InV().Limit<object>(3)}}, 
+               {"g_VX1X_outXknowsX_outEXcreatedX_rangeX0_1X_inV", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out("knows").OutE("created").Range<object>(0,1).InV()}}, 
+               {"g_VX1X_outXknowsX_outXcreatedX_rangeX0_1X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out("knows").Out("created").Range<object>(0,1)}}, 
+               {"g_VX1X_outXcreatedX_inXcreatedX_rangeX1_3X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out("created").In("created").Range<object>(1,3)}}, 
+               {"g_VX1X_outXcreatedX_inEXcreatedX_rangeX1_3X_outV", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out("created").InE("created").Range<object>(1,3).OutV()}}, 
+               {"g_V_repeatXbothX_timesX3X_rangeX5_11X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Repeat(__.Both()).Times(3).Range<object>(5,11)}}, 
+               {"g_V_asXaX_in_asXbX_in_asXcX_selectXa_b_cX_byXnameX_limitXlocal_2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").In().As("b").In().As("c").Select<object>("a","b","c").By("name").Limit<object>(Scope.Local,2)}}, 
+               {"g_V_asXaX_in_asXbX_in_asXcX_selectXa_b_cX_byXnameX_limitXlocal_1X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").In().As("b").In().As("c").Select<object>("a","b","c").By("name").Limit<object>(Scope.Local,1)}}, 
+               {"g_V_asXaX_out_asXbX_out_asXcX_selectXa_b_cX_byXnameX_rangeXlocal_1_3X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out().As("b").Out().As("c").Select<object>("a","b","c").By("name").Range<object>(Scope.Local,1,3)}}, 
+               {"g_V_asXaX_out_asXbX_out_asXcX_selectXa_b_cX_byXnameX_rangeXlocal_1_2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out().As("b").Out().As("c").Select<object>("a","b","c").By("name").Range<object>(Scope.Local,1,2)}}, 
+               {"g_V_asXaX_out_asXaX_out_asXaX_selectXmixed_aX_byXunfold_valuesXnameX_foldX_rangeXlocal_1_3X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out().As("a").Out().As("a").Select<object>(Pop.Mixed,"a").By(__.Unfold<object>().Values<object>("name").Fold()).Range<object>(Scope.Local,1,3)}}, 
+               {"g_V_asXaX_out_asXaX_out_asXaX_selectXmixed_aX_byXunfold_valuesXnameX_foldX_rangeXlocal_1_2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out().As("a").Out().As("a").Select<object>(Pop.Mixed,"a").By(__.Unfold<object>().Values<object>("name").Fold()).Range<object>(Scope.Local,1,2)}}, 
+               {"g_V_hasLabelXpersonX_order_byXageX_skipX1X_valuesXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Order().By("age").Skip<object>(1).Values<object>("name")}}, 
+               {"g_V_asXaX_out_asXaX_out_asXaX_selectXmixed_aX_byXunfold_valuesXnameX_foldX_rangeXlocal_4_5X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out().As("a").Out().As("a").Select<object>(Pop.Mixed,"a").By(__.Unfold<object>().Values<object>("name").Fold()).Range<object>(Scope.Local,4,5)}}, 
+               {"g_V_outE_valuesXweightX_fold_orderXlocalX_skipXlocal_2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().OutE().Values<object>("weight").Fold().Order(Scope.Local).Skip<object>(Scope.Local,2)}}, 
+               {"g_V_asXaX_in_asXaX_in_asXaX_selectXmixed_aX_byXunfold_valuesXnameX_foldX_limitXlocal_1X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").In().As("a").In().As("a").Select<object>(Pop.Mixed,"a").By(__.Unfold<object>().Values<object>("name").Fold()).Limit<object>(Scope.Local,1)}}, 
+               {"g_V_asXaX_in_asXaX_in_asXaX_selectXmixed_aX_byXunfold_valuesXnameX_foldX_limitXlocal_2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").In().As("a").In().As("a").Select<object>(Pop.Mixed,"a").By(__.Unfold<object>().Values<object>("name").Fold()).Limit<object>(Scope.Local,2)}}, 
+               {"g_V_hasLabelXpersonX_order_byXageX_valuesXnameX_skipX1X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Order().By("age").Values<object>("name").Skip<object>(1)}}, 
+               {"g_E_sampleX1X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E().Sample(1)}}, 
+               {"g_E_sampleX2X_byXweightX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E().Sample(2).By("weight")}}, 
+               {"g_V_localXoutE_sampleX1X_byXweightXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Local<object>(__.OutE().Sample(1).By("weight"))}}, 
+               {"g_V_group_byXlabelX_byXbothE_weight_sampleX2X_foldX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Group<object,object>().By(T.Label).By(__.BothE().Values<object>("weight").Sample(2).Fold())}}, 
+               {"g_V_group_byXlabelX_byXbothE_weight_fold_sampleXlocal_5XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Group<object,object>().By(T.Label).By(__.BothE().Values<object>("weight").Fold().Sample(Scope.Local,5))}}, 
+               {"g_VX1X_outXcreatedX_inXcreatedX_simplePath", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out("created").In("created").SimplePath()}}, 
+               {"g_V_repeatXboth_simplePathX_timesX3X_path", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Repeat(__.Both().SimplePath()).Times(3).Path()}}, 
+               {"g_V_asXaX_out_asXbX_out_asXcX_simplePath_byXlabelX_fromXbX_toXcX_path_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out().As("b").Out().As("c").SimplePath().By(T.Label).From("b").To("c").Path().By("name")}}, 
+               {"g_V_valuesXnameX_order_tailXglobal_2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Order().Tail<object>(Scope.Global,2)}}, 
+               {"g_V_valuesXnameX_order_tailX2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Order().Tail<object>(2)}}, 
+               {"g_V_valuesXnameX_order_tail", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Order().Tail<object>()}}, 
+               {"g_V_valuesXnameX_order_tailX7X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Order().Tail<object>(7)}}, 
+               {"g_V_repeatXbothX_timesX3X_tailX7X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Repeat(__.Both()).Times(3).Tail<object>(7)}}, 
+               {"g_V_repeatXin_outX_timesX3X_tailX7X_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Repeat(__.In().Out()).Times(3).Tail<object>(7).Count()}}, 
+               {"g_V_asXaX_out_asXaX_out_asXaX_selectXaX_byXunfold_valuesXnameX_foldX_tailXlocal_1X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out().As("a").Out().As("a").Select<object>("a").By(__.Unfold<object>().Values<object>("name").Fold()).Tail<object>(Scope.Local,1)}}, 
+               {"g_V_asXaX_out_asXaX_out_asXaX_selectXaX_byXunfold_valuesXnameX_foldX_tailXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out().As("a").Out().As("a").Select<object>("a").By(__.Unfold<object>().Values<object>("name").Fold()).Tail<object>(Scope.Local)}}, 
+               {"g_V_asXaX_out_asXbX_out_asXcX_selectXa_b_cX_byXnameX_tailXlocal_2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out().As("b").Out().As("c").Select<object>("a","b","c").By("name").Tail<object>(Scope.Local,2)}}, 
+               {"g_V_asXaX_out_asXbX_out_asXcX_selectXa_b_cX_byXnameX_tailXlocal_1X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out().As("b").Out().As("c").Select<object>("a","b","c").By("name").Tail<object>(Scope.Local,1)}}, 
+               {"g_V_asXaX_out_asXaX_out_asXaX_selectXmixed_aX_byXunfold_valuesXnameX_foldX_tailXlocal_1X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out().As("a").Out().As("a").Select<object>(Pop.Mixed,"a").By(__.Unfold<object>().Values<object>("name").Fold()).Tail<object>(Scope.Local,1)}}, 
+               {"g_V_asXaX_out_asXaX_out_asXaX_selectXmixed_aX_byXunfold_valuesXnameX_foldX_tailXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out().As("a").Out().As("a").Select<object>(Pop.Mixed,"a").By(__.Unfold<object>().Values<object>("name").Fold()).Tail<object>(Scope.Local)}}, 
+               {"g_V_asXaX_out_asXaX_out_asXaX_selectXmixed_aX_byXlimitXlocal_0XX_tailXlocal_1X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out().As("a").Out().As("a").Select<object>(Pop.Mixed,"a").By(__.Limit<object>(Scope.Local,0)).Tail<object>(Scope.Local,1)}}, 
+               {"g_V_asXaX_out_asXaX_out_asXaX_selectXmixed_aX_byXunfold_valuesXnameX_foldX_tailXlocal_2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out().As("a").Out().As("a").Select<object>(Pop.Mixed,"a").By(__.Unfold<object>().Values<object>("name").Fold()).Tail<object>(Scope.Local,2)}}, 
+               {"g_V_hasXageX_asXaX_out_in_hasXageX_asXbX_selectXa_bX_whereXa_eqXbXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age").As("a").Out().In().Has("age").As("b").Select<object>("a","b").Where("a",P.Eq("b"))}}, 
+               {"g_V_hasXageX_asXaX_out_in_hasXageX_asXbX_selectXa_bX_whereXa_neqXbXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age").As("a").Out().In().Has("age").As("b").Select<object>("a","b").Where("a",P.Neq("b"))}}, 
+               {"g_V_hasXageX_asXaX_out_in_hasXageX_asXbX_selectXa_bX_whereXb_hasXname_markoXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age").As("a").Out().In().Has("age").As("b").Select<object>("a","b").Where(__.As("b").Has("name","marko"))}}, 
+               {"g_V_hasXageX_asXaX_out_in_hasXageX_asXbX_selectXa_bX_whereXa_outXknowsX_bX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age").As("a").Out().In().Has("age").As("b").Select<object>("a","b").Where(__.As("a").Out("knows").As("b"))}}, 
+               {"g_V_asXaX_outXcreatedX_whereXasXaX_name_isXjoshXX_inXcreatedX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out("created").Where(__.As("a").Values<object>("name").Is("josh")).In("created").Values<object>("name")}}, 
+               {"g_withSideEffectXa_josh_peterX_VX1X_outXcreatedX_inXcreatedX_name_whereXwithinXaXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithSideEffect("a",p["xx1"]).V(p["vid1"]).Out("created").In("created").Values<object>("name").Where(P.Within(new List<object> {"a"}))}}, 
+               {"g_VX1X_asXaX_outXcreatedX_inXcreatedX_asXbX_whereXa_neqXbXX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).As("a").Out("created").In("created").As("b").Where("a",P.Neq("b")).Values<object>("name")}}, 
+               {"g_VX1X_asXaX_outXcreatedX_inXcreatedX_asXbX_whereXasXbX_outXcreatedX_hasXname_rippleXX_valuesXage_nameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).As("a").Out("created").In("created").As("b").Where(__.As("b").Out("created").Has("name","ripple")).Values<object>("age","name")}}, 
+               {"g_VX1X_asXaX_outXcreatedX_inXcreatedX_whereXeqXaXX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).As("a").Out("created").In("created").Where(P.Eq("a")).Values<object>("name")}}, 
+               {"g_VX1X_asXaX_outXcreatedX_inXcreatedX_whereXneqXaXX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).As("a").Out("created").In("created").Where(P.Neq("a")).Values<object>("name")}}, 
+               {"g_VX1X_out_aggregateXxX_out_whereXnotXwithinXaXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out().Aggregate("x").Out().Where(P.Without(new List<object> {"x"}))}}, 
+               {"g_withSideEffectXa_g_VX2XX_VX1X_out_whereXneqXaXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithSideEffect("a",(Vertex) p["v2"]).V(p["vid1"]).Out().Where(P.Neq("a"))}}, 
+               {"g_VX1X_repeatXbothEXcreatedX_whereXwithoutXeXX_aggregateXeX_otherVX_emit_path", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Repeat(__.BothE("created").Where(P.Without(new List<object> {"e"})).Aggregate("e").OtherV()).Emit().Path()}}, 
+               {"g_V_whereXnotXoutXcreatedXXX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Where(__.Not(__.Out("created"))).Values<object>("name")}}, 
+               {"g_V_asXaX_out_asXbX_whereXandXasXaX_outXknowsX_asXbX__orXasXbX_outXcreatedX_hasXname_rippleX__asXbX_inXknowsX_count_isXnotXeqX0XXXXX_selectXa_bX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out().As("b").Where(__.And(__.As("a").Out("knows").As("b"),__.Or(__.As("b").Out("created").Has("name","ripple"),__.As("b").In("knows").Count().Is(P.Neq(0))))).Select<object>("a","b")}}, 
+               {"g_V_whereXoutXcreatedX_and_outXknowsX_or_inXknowsXX_valuesXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Where(__.Out("created").And().Out("knows").Or().In("knows")).Values<object>("name")}}, 
+               {"g_V_asXaX_outXcreatedX_asXbX_whereXandXasXbX_in__notXasXaX_outXcreatedX_hasXname_rippleXXX_selectXa_bX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out("created").As("b").Where(__.And(__.As("b").In(),__.Not(__.As("a").Out("created").Has("name","ripple")))).Select<object>("a","b")}}, 
+               {"g_V_asXaX_outXcreatedX_asXbX_inXcreatedX_asXcX_bothXknowsX_bothXknowsX_asXdX_whereXc__notXeqXaX_orXeqXdXXXX_selectXa_b_c_dX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out("created").As("b").In("created").As("c").Both("knows").Both("knows").As("d").Where("c",P.Neq("a").And(P.Neq("d"))).Select<object>("a","b","c","d")}}, 
+               {"g_V_asXaX_out_asXbX_whereXin_count_isXeqX3XX_or_whereXoutXcreatedX_and_hasXlabel_personXXX_selectXa_bX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out().As("b").Where(__.As("b").In().Count().Is(P.Eq(3)).Or().Where(__.As("b").Out("created").And().As("b").Has(T.Label,"person"))).Select<object>("a","b")}}, 
+               {"g_V_asXaX_outXcreatedX_inXcreatedX_asXbX_whereXa_gtXbXX_byXageX_selectXa_bX_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out("created").In("created").As("b").Where("a",P.Gt("b")).By("age").Select<object>("a","b").By("name")}}, 
+               {"g_V_asXaX_outEXcreatedX_asXbX_inV_asXcX_whereXa_gtXbX_orXeqXbXXX_byXageX_byXweightX_byXweightX_selectXa_cX_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").OutE("created").As("b").InV().As("c").Where("a",P.Gt("b").Or(P.Eq("b"))).By("age").By("weight").By("weight").Select<object>("a","c").By("name")}}, 
+               {"g_V_asXaX_outEXcreatedX_asXbX_inV_asXcX_inXcreatedX_asXdX_whereXa_ltXbX_orXgtXcXX_andXneqXdXXX_byXageX_byXweightX_byXinXcreatedX_valuesXageX_minX_selectXa_c_dX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").OutE("created").As("b").InV().As("c").In("created").As("d").Where("a",P.Lt("b").Or(P.Gt("c")).And(P.Neq("d"))).By("age").By("weight").By(__.In("created").Values<object>("age").Min<object>()).Select<object>("a","c","d").By("name")}}, 
+               {"g_VX1X_asXaX_out_hasXageX_whereXgtXaXX_byXageX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).As("a").Out().Has("age").Where(P.Gt("a")).By("age").Values<object>("name")}}, 
+               {"g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").AddV("software").Property(T.Id,5).Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property(T.Id,6).Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property(T.Id,7).Property("weight",0.5).AddE("knows").From("marko").To("josh").Property(T.Id,8).Property("weight",1.0).AddE("created").From("marko").To("lop").Property(T.Id,9).Property("weight",0.4).AddE("created").From("josh").To("ripple").Property(T.Id,10).Property("weight",1.0).AddE("created").From("josh").To("lop").Property(T.Id,11).Property("weight",0.4).AddE("created").From("peter").To("lop").Property(T.Id,12).Property("weight",0.2), (g,p) =>g.V(p["vid1"]).As("a").Out("created").AddE("createdBy").To("a"), (g,p) =>g.E(), (g,p) =>g.V(p["vid1"]).InE()}}, 
+               {"g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX_propertyXweight_2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").AddV("software").Property(T.Id,5).Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property(T.Id,6).Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property(T.Id,7).Property("weight",0.5).AddE("knows").From("marko").To("josh").Property(T.Id,8).Property("weight",1.0).AddE("created").From("marko").To("lop").Property(T.Id,9).Property("weight",0.4).AddE("created").From("josh").To("ripple").Property(T.Id,10).Property("weight",1.0).AddE("created").From("josh").To("lop").Property(T.Id,11).Property("weight",0.4).AddE("created").From("peter").To("lop").Property(T.Id,12).Property("weight",0.2), (g,p) =>g.V(p["vid1"]).As("a").Out("created").AddE("createdBy").To("a").Property("weight",2.0), (g,p) =>g.E(), (g,p) =>g.V(p["vid1"]).BothE(), (g,p) =>g.V(p["vid1"]).InE().Has("weight",2.0)}}, 
+               {"g_V_outE_propertyXweight_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").AddV("software").Property(T.Id,5).Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property(T.Id,6).Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property(T.Id,7).Property("weight",0.5).AddE("knows").From("marko").To("josh").Property(T.Id,8).Property("weight",1.0).AddE("created").From("marko").To("lop").Property(T.Id,9).Property("weight",0.4).AddE("created").From("josh").To("ripple").Property(T.Id,10).Property("weight",1.0).AddE("created").From("josh").To("lop").Property(T.Id,11).Property("weight",0.4).AddE("created").From("peter").To("lop").Property(T.Id,12).Property("weight",0.2), (g,p) =>g.V().OutE().Property("weight",null), (g,p) =>g.E().Properties<object>("weight")}}, 
+               {"g_V_aggregateXxX_asXaX_selectXxX_unfold_addEXexistsWithX_toXaX_propertyXtime_nowX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").AddV("software").Property(T.Id,5).Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property(T.Id,6).Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property(T.Id,7).Property("weight",0.5).AddE("knows").From("marko").To("josh").Property(T.Id,8).Property("weight",1.0).AddE("created").From("marko").To("lop").Property(T.Id,9).Property("weight",0.4).AddE("created").From("josh").To("ripple").Property(T.Id,10).Property("weight",1.0).AddE("created").From("josh").To("lop").Property(T.Id,11).Property("weight",0.4).AddE("created").From("peter").To("lop").Property(T.Id,12).Property("weight",0.2), (g,p) =>g.V().Aggregate("x").As("a").Select<object>("x").Unfold<object>().AddE("existsWith").To("a").Property("time","now"), (g,p) =>g.E(), (g,p) =>g.V(p["vid1"]).BothE(), (g,p) =>g.V(p["vid1"]).InE("existsWith"), (g,p) =>g.V(p["vid1"]).OutE("existsWith"), (g,p) =>g.V(p["vid1"]).BothE("existsWith").Has("time","now"), (g,p) =>g.V(p["vid2"]).BothE(), (g,p) =>g.V(p["vid2"]).InE("existsWith"), (g,p) =>g.V(p["vid2"]).OutE("existsWith"), (g,p) =>g.V(p["vid2"]).BothE("existsWith").Has("time","now"), (g,p) =>g.V(p["vid3"]).BothE(), (g,p) =>g.V(p["vid3"]).InE("existsWith"), (g,p) =>g.V(p["vid3"]).OutE("existsWith"), (g,p) =>g.V(p["vid3"]).BothE("existsWith").Has("time","now"), (g,p) =>g.V(p["vid4"]).BothE(), (g,p) =>g.V(p["vid4"]).InE("existsWith"), (g,p) =>g.V(p["vid4"]).OutE("existsWith"), (g,p) =>g.V(p["vid4"]).BothE("existsWith").Has("time","now"), (g,p) =>g.V(p["vid5"]).BothE(), (g,p) =>g.V(p["vid5"]).InE("existsWith"), (g,p) =>g.V(p["vid5"]).OutE("existsWith"), (g,p) =>g.V(p["vid5"]).BothE("existsWith").Has("time","now"), (g,p) =>g.V(p["vid6"]).BothE(), (g,p) =>g.V(p["vid6"]).InE("existsWith"), (g,p) =>g.V(p["vid6"]).OutE("existsWith"), (g,p) =>g.V(p["vid6"]).BothE("existsWith").Has("time","now")}}, 
+               {"g_V_asXaX_outXcreatedX_inXcreatedX_whereXneqXaXX_asXbX_addEXcodeveloperX_fromXaX_toXbX_propertyXyear_2009X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").AddV("software").Property(T.Id,5).Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property(T.Id,6).Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property(T.Id,7).Property("weight",0.5).AddE("knows").From("marko").To("josh").Property(T.Id,8).Property("weight",1.0).AddE("created").From("marko").To("lop").Property(T.Id,9).Property("weight",0.4).AddE("created").From("josh").To("ripple").Property(T.Id,10).Property("weight",1.0).AddE("created").From("josh").To("lop").Property(T.Id,11).Property("weight",0.4).AddE("created").From("peter").To("lop").Property(T.Id,12).Property("weight",0.2), (g,p) =>g.V().As("a").Out("created").In("created").Where(P.Neq("a")).As("b").AddE("codeveloper").From("a").To("b").Property("year",2009), (g,p) =>g.E(), (g,p) =>g.V(p["vid1"]).BothE(), (g,p) =>g.V(p["vid1"]).InE("codeveloper"), (g,p) =>g.V(p["vid1"]).OutE("codeveloper"), (g,p) =>g.V(p["vid1"]).BothE("codeveloper").Has("year",2009), (g,p) =>g.V(p["vid2"]).BothE(), (g,p) =>g.V(p["vid4"]).BothE(), (g,p) =>g.V(p["vid4"]).InE("codeveloper"), (g,p) =>g.V(p["vid4"]).OutE("codeveloper"), (g,p) =>g.V(p["vid4"]).BothE("codeveloper").Has("year",2009), (g,p) =>g.V(p["vid6"]).BothE(), (g,p) =>g.V(p["vid6"]).InE("codeveloper"), (g,p) =>g.V(p["vid6"]).OutE("codeveloper"), (g,p) =>g.V(p["vid6"]).BothE("codeveloper").Has("year",2009)}}, 
+               {"g_V_asXaX_inXcreatedX_addEXcreatedByX_fromXaX_propertyXyear_2009X_propertyXacl_publicX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").AddV("software").Property(T.Id,5).Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property(T.Id,6).Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property(T.Id,7).Property("weight",0.5).AddE("knows").From("marko").To("josh").Property(T.Id,8).Property("weight",1.0).AddE("created").From("marko").To("lop").Property(T.Id,9).Property("weight",0.4).AddE("created").From("josh").To("ripple").Property(T.Id,10).Property("weight",1.0).AddE("created").From("josh").To("lop").Property(T.Id,11).Property("weight",0.4).AddE("created").From("peter").To("lop").Property(T.Id,12).Property("weight",0.2), (g,p) =>g.V().As("a").In("created").AddE("createdBy").From("a").Property("year",2009).Property("acl","public"), (g,p) =>g.E(), (g,p) =>g.V(p["vid1"]).BothE(), (g,p) =>g.V(p["vid1"]).InE("createdBy"), (g,p) =>g.V(p["vid1"]).OutE("createdBy"), (g,p) =>g.V(p["vid1"]).BothE("createdBy").Has("year",2009).Has("acl","public"), (g,p) =>g.V(p["vid2"]).BothE(), (g,p) =>g.V(p["vid3"]).BothE(), (g,p) =>g.V(p["vid3"]).InE("createdBy"), (g,p) =>g.V(p["vid3"]).OutE("createdBy"), (g,p) =>g.V(p["vid3"]).BothE("createdBy").Has("year",2009).Has("acl","public"), (g,p) =>g.V(p["vid4"]).BothE(), (g,p) =>g.V(p["vid4"]).InE("createdBy"), (g,p) =>g.V(p["vid4"]).OutE("createdBy"), (g,p) =>g.V(p["vid4"]).BothE("createdBy").Has("year",2009).Has("acl","public"), (g,p) =>g.V(p["vid5"]).BothE(), (g,p) =>g.V(p["vid5"]).InE("createdBy"), (g,p) =>g.V(p["vid5"]).OutE("createdBy"), (g,p) =>g.V(p["vid5"]).BothE("createdBy").Has("year",2009).Has("acl","public"), (g,p) =>g.V(p["vid6"]).BothE(), (g,p) =>g.V(p["vid6"]).InE("createdBy"), (g,p) =>g.V(p["vid6"]).OutE("createdBy"), (g,p) =>g.V(p["vid6"]).BothE("createdBy").Has("year",2009).Has("acl","public")}}, 
+               {"g_withSideEffectXb_bX_VXaX_addEXknowsX_toXbX_propertyXweight_0_5X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").AddV("software").Property(T.Id,5).Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property(T.Id,6).Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property(T.Id,7).Property("weight",0.5).AddE("knows").From("marko").To("josh").Property(T.Id,8).Property("weight",1.0).AddE("created").From("marko").To("lop").Property(T.Id,9).Property("weight",0.4).AddE("created").From("josh").To("ripple").Property(T.Id,10).Property("weight",1.0).AddE("created").From("josh").To("lop").Property(T.Id,11).Property("weight",0.4).AddE("created").From("peter").To("lop").Property(T.Id,12).Property("weight",0.2), (g,p) =>g.WithSideEffect("b",(Vertex) p["v6"]).V((Vertex) p["v1"]).AddE("knows").To("b").Property("weight",0.5), (g,p) =>g.E(), (g,p) =>g.V((Vertex) p["v1"]).BothE(), (g,p) =>g.V((Vertex) p["v1"]).InE("knows"), (g,p) =>g.V((Vertex) p["v1"]).OutE("knows"), (g,p) =>g.V((Vertex) p["v1"]).BothE("knows").Has("weight",0.5), (g,p) =>g.V((Vertex) p["v6"]).BothE(), (g,p) =>g.V((Vertex) p["v6"]).InE("knows"), (g,p) =>g.V((Vertex) p["v6"]).OutE("knows"), (g,p) =>g.V((Vertex) p["v6"]).BothE("knows").Has("weight",0.5)}}, 
+               {"g_addV_asXfirstX_repeatXaddEXnextX_toXaddVX_inVX_timesX5X_addEXnextX_toXselectXfirstXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV().As("first").Repeat(__.AddE("next").To(__.AddV()).InV()).Times(5).AddE("next").To(__.Select<object>("first")), (g,p) =>g.V(), (g,p) =>g.E(), (g,p) =>g.E().HasLabel("next"), (g,p) =>g.V().Limit<object>(1).BothE(), (g,p) =>g.V().Limit<object>(1).InE(), (g,p) =>g.V().Limit<object>(1).OutE()}}, 
+               {"g_V_hasXname_markoX_asXaX_outEXcreatedX_asXbX_inV_addEXselectXbX_labelX_toXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").AddV("software").Property(T.Id,5).Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property(T.Id,6).Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property(T.Id,7).Property("weight",0.5).AddE("knows").From("marko").To("josh").Property(T.Id,8).Property("weight",1.0).AddE("created").From("marko").To("lop").Property(T.Id,9).Property("weight",0.4).AddE("created").From("josh").To("ripple").Property(T.Id,10).Property("weight",1.0).AddE("created").From("josh").To("lop").Property(T.Id,11).Property("weight",0.4).AddE("created").From("peter").To("lop").Property(T.Id,12).Property("weight",0.2), (g,p) =>g.V().Has("name","marko").As("a").OutE("created").As("b").InV().AddE(__.Select<object>("b").Label()).To("a"), (g,p) =>g.E(), (g,p) =>g.V((Vertex) p["v1"]).BothE(), (g,p) =>g.V((Vertex) p["v1"]).InE("created"), (g,p) =>g.V((Vertex) p["v1"]).In("created").Has("name","lop"), (g,p) =>g.V((Vertex) p["v1"]).OutE("created")}}, 
+               {"g_addEXV_outE_label_groupCount_orderXlocalX_byXvalues_descX_selectXkeysX_unfold_limitX1XX_fromXV_hasXname_vadasXX_toXV_hasXname_lopXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").AddV("software").Property(T.Id,5).Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property(T.Id,6).Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property(T.Id,7).Property("weight",0.5).AddE("knows").From("marko").To("josh").Property(T.Id,8).Property("weight",1.0).AddE("created").From("marko").To("lop").Property(T.Id,9).Property("weight",0.4).AddE("created").From("josh").To("ripple").Property(T.Id,10).Property("weight",1.0).AddE("created").From("josh").To("lop").Property(T.Id,11).Property("weight",0.4).AddE("created").From("peter").To("lop").Property(T.Id,12).Property("weight",0.2), (g,p) =>g.AddE(__.V().OutE().Label().GroupCount<object>().Order(Scope.Local).By(Column.Values,Order.Desc).Select<object>(Column.Keys).Unfold<object>().Limit<object>(1)).From(__.V().Has("name","vadas")).To(__.V().Has("name","lop")), (g,p) =>g.E(), (g,p) =>g.V((Vertex) p["v2"]).BothE(), (g,p) =>g.V((Vertex) p["v2"]).InE("knows"), (g,p) =>g.V((Vertex) p["v2"]).OutE("created"), (g,p) =>g.V((Vertex) p["v2"]).Out("created").Has("name","lop")}}, 
+               {"g_addEXknowsX_fromXaX_toXbX_propertyXweight_0_1X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").AddV("software").Property(T.Id,5).Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property(T.Id,6).Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property(T.Id,7).Property("weight",0.5).AddE("knows").From("marko").To("josh").Property(T.Id,8).Property("weight",1.0).AddE("created").From("marko").To("lop").Property(T.Id,9).Property("weight",0.4).AddE("created").From("josh").To("ripple").Property(T.Id,10).Property("weight",1.0).AddE("created").From("josh").To("lop").Property(T.Id,11).Property("weight",0.4).AddE("created").From("peter").To("lop").Property(T.Id,12).Property("weight",0.2), (g,p) =>g.AddE("knows").From((Vertex) p["v1"]).To((Vertex) p["v6"]).Property("weight",p["xx1"]), (g,p) =>g.E(), (g,p) =>g.V((Vertex) p["v1"]).OutE("knows"), (g,p) =>g.V((Vertex) p["v1"]).Out("knows").Has("name","peter")}}, 
+               {"g_VXaX_addEXknowsX_toXbX_propertyXweight_0_1X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").AddV("software").Property(T.Id,5).Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property(T.Id,6).Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property(T.Id,7).Property("weight",0.5).AddE("knows").From("marko").To("josh").Property(T.Id,8).Property("weight",1.0).AddE("created").From("marko").To("lop").Property(T.Id,9).Property("weight",0.4).AddE("created").From("josh").To("ripple").Property(T.Id,10).Property("weight",1.0).AddE("created").From("josh").To("lop").Property(T.Id,11).Property("weight",0.4).AddE("created").From("peter").To("lop").Property(T.Id,12).Property("weight",0.2), (g,p) =>g.V((Vertex) p["v1"]).AddE("knows").To((Vertex) p["v6"]).Property("weight",p["xx1"]), (g,p) =>g.E(), (g,p) =>g.V((Vertex) p["v1"]).OutE("knows"), (g,p) =>g.V((Vertex) p["v1"]).Out("knows").Has("name","peter")}}, 
+               {"g_VX1X_addVXanimalX_propertyXage_selectXaX_byXageXX_propertyXname_puppyX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").AddV("software").Property(T.Id,5).Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property(T.Id,6).Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property(T.Id,7).Property("weight",0.5).AddE("knows").From("marko").To("josh").Property(T.Id,8).Property("weight",1.0).AddE("created").From("marko").To("lop").Property(T.Id,9).Property("weight",0.4).AddE("created").From("josh").To("ripple").Property(T.Id,10).Property("weight",1.0).AddE("created").From("josh").To("lop").Property(T.Id,11).Property("weight",0.4).AddE("created").From("peter").To("lop").Property(T.Id,12).Property("weight",0.2), (g,p) =>g.V(p["vid1"]).As("a").AddV("animal").Property("age",__.Select<object>("a").By("age")).Property("name","puppy"), (g,p) =>g.V().Has("animal","age",29)}}, 
+               {"g_V_addVXanimalX_propertyXage_0X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").AddV("software").Property(T.Id,5).Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property(T.Id,6).Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property(T.Id,7).Property("weight",0.5).AddE("knows").From("marko").To("josh").Property(T.Id,8).Property("weight",1.0).AddE("created").From("marko").To("lop").Property(T.Id,9).Property("weight",0.4).AddE("created").From("josh").To("ripple").Property(T.Id,10).Property("weight",1.0).AddE("created").From("josh").To("lop").Property(T.Id,11).Property("weight",0.4).AddE("created").From("peter").To("lop").Property(T.Id,12).Property("weight",0.2), (g,p) =>g.V().AddV("animal").Property("age",0), (g,p) =>g.V().Has("animal","age",0)}}, 
+               {"g_addVXpersonX_propertyXname_stephenX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").AddV("software").Property(T.Id,5).Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property(T.Id,6).Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property(T.Id,7).Property("weight",0.5).AddE("knows").From("marko").To("josh").Property(T.Id,8).Property("weight",1.0).AddE("created").From("marko").To("lop").Property(T.Id,9).Property("weight",0.4).AddE("created").From("josh").To("ripple").Property(T.Id,10).Property("weight",1.0).AddE("created").From("josh").To("lop").Property(T.Id,11).Property("weight",0.4).AddE("created").From("peter").To("lop").Property(T.Id,12).Property("weight",0.2), (g,p) =>g.AddV("person").Property("name","stephen"), (g,p) =>g.V().Has("person","name","stephen")}}, 
+               {"g_V_hasLabelXpersonX_propertyXname_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").AddV("software").Property(T.Id,5).Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property(T.Id,6).Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property(T.Id,7).Property("weight",0.5).AddE("knows").From("marko").To("josh").Property(T.Id,8).Property("weight",1.0).AddE("created").From("marko").To("lop").Property(T.Id,9).Property("weight",0.4).AddE("created").From("josh").To("ripple").Property(T.Id,10).Property("weight",1.0).AddE("created").From("josh").To("lop").Property(T.Id,11).Property("weight",0.4).AddE("created").From("peter").To("lop").Property(T.Id,12).Property("weight",0.2), (g,p) =>g.V().HasLabel("person").Property("name",null), (g,p) =>g.V().Properties<object>("name")}}, 
+               {"g_addVXpersonX_propertyXsingle_name_stephenX_propertyXsingle_name_stephenmX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").AddV("software").Property(T.Id,5).Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property(T.Id,6).Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property(T.Id,7).Property("weight",0.5).AddE("knows").From("marko").To("josh").Property(T.Id,8).Property("weight",1.0).AddE("created").From("marko").To("lop").Property(T.Id,9).Property("weight",0.4).AddE("created").From("josh").To("ripple").Property(T.Id,10).Property("weight",1.0).AddE("created").From("josh").To("lop").Property(T.Id,11).Property("weight",0.4).AddE("created").From("peter").To("lop").Property(T.Id,12).Property("weight",0.2), (g,p) =>g.AddV("person").Property(Cardinality.Single,"name","stephen").Property(Cardinality.Single,"name","stephenm"), (g,p) =>g.V().Has("person","name","stephen"), (g,p) =>g.V().Has("person","name","stephenm")}}, 
+               {"get_g_addVXpersonX_propertyXsingle_name_stephenX_propertyXsingle_name_stephenm_since_2010X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").AddV("software").Property(T.Id,5).Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property(T.Id,6).Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property(T.Id,7).Property("weight",0.5).AddE("knows").From("marko").To("josh").Property(T.Id,8).Property("weight",1.0).AddE("created").From("marko").To("lop").Property(T.Id,9).Property("weight",0.4).AddE("created").From("josh").To("ripple").Property(T.Id,10).Property("weight",1.0).AddE("created").From("josh").To("lop").Property(T.Id,11).Property("weight",0.4).AddE("created").From("peter").To("lop").Property(T.Id,12).Property("weight",0.2), (g,p) =>g.AddV("person").Property(Cardinality.Single,"name","stephen").Property(Cardinality.Single,"name","stephenm","since",2010), (g,p) =>g.V().Has("person","name","stephen"), (g,p) =>g.V().Has("person","name","stephenm"), (g,p) =>g.V().Has("person","name","stephenm").Properties<object>("name").Has("since",2010)}}, 
+               {"g_V_hasXname_markoX_propertyXfriendWeight_outEXknowsX_weight_sum__acl_privateX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").AddV("software").Property(T.Id,5).Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property(T.Id,6).Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property(T.Id,7).Property("weight",0.5).AddE("knows").From("marko").To("josh").Property(T.Id,8).Property("weight",1.0).AddE("created").From("marko").To("lop").Property(T.Id,9).Property("weight",0.4).AddE("created").From("josh").To("ripple").Property(T.Id,10).Property("weight",1.0).AddE("created").From("josh").To("lop").Property(T.Id,11).Property("weight",0.4).AddE("created").From("peter").To("lop").Property(T.Id,12).Property("weight",0.2), (g,p) =>g.V().Has("name","marko").Property("friendWeight",__.OutE("knows").Values<object>("weight").Sum<object>(),"acl","private"), (g,p) =>g.V().Has("person","name","marko").Has("friendWeight",1.5), (g,p) =>g.V().Has("person","name","marko").Properties<object>("friendWeight").Has("acl","private"), (g,p) =>g.V().Has("person","name","marko").Properties<object>("friendWeight").Count()}}, 
+               {"g_addVXanimalX_propertyXname_mateoX_propertyXname_gateoX_propertyXname_cateoX_propertyXage_5X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").AddV("software").Property(T.Id,5).Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property(T.Id,6).Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property(T.Id,7).Property("weight",0.5).AddE("knows").From("marko").To("josh").Property(T.Id,8).Property("weight",1.0).AddE("created").From("marko").To("lop").Property(T.Id,9).Property("weight",0.4).AddE("created").From("josh").To("ripple").Property(T.Id,10).Property("weight",1.0).AddE("created").From("josh").To("lop").Property(T.Id,11).Property("weight",0.4).AddE("created").From("peter").To("lop").Property(T.Id,12).Property("weight",0.2), (g,p) =>g.AddV("animal").Property("name","mateo").Property("name","gateo").Property("name","cateo").Property("age",5), (g,p) =>g.V().HasLabel("animal").Has("name","mateo").Has("name","gateo").Has("name","cateo").Has("age",5)}}, 
+               {"g_withSideEffectXa_markoX_addV_propertyXname_selectXaXX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").AddV("software").Property(T.Id,5).Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property(T.Id,6).Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property(T.Id,7).Property("weight",0.5).AddE("knows").From("marko").To("josh").Property(T.Id,8).Property("weight",1.0).AddE("created").From("marko").To("lop").Property(T.Id,9).Property("weight",0.4).AddE("created").From("josh").To("ripple").Property(T.Id,10).Property("weight",1.0).AddE("created").From("josh").To("lop").Property(T.Id,11).Property("weight",0.4).AddE("created").From("peter").To("lop").Property(T.Id,12).Property("weight",0.2), (g,p) =>g.WithSideEffect("a","marko").AddV().Property("name",__.Select<object>("a")).Values<object>("name"), (g,p) =>g.V().Has("name","marko")}}, 
+               {"g_addVXpersonX_propertyXsingle_name_stephenX_propertyXsingle_name_stephenm_since_2010X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").AddV("software").Property(T.Id,5).Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property(T.Id,6).Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property(T.Id,7).Property("weight",0.5).AddE("knows").From("marko").To("josh").Property(T.Id,8).Property("weight",1.0).AddE("created").From("marko").To("lop").Property(T.Id,9).Property("weight",0.4).AddE("created").From("josh").To("ripple").Property(T.Id,10).Property("weight",1.0).AddE("created").From("josh").To("lop").Property(T.Id,11).Property("weight",0.4).AddE("created").From("peter").To("lop").Property(T.Id,12).Property("weight",0.2), (g,p) =>g.AddV("person").Property(Cardinality.Single,"name","stephen").Property(Cardinality.Single,"name","stephenm","since",2010), (g,p) =>g.V().Has("name","stephen"), (g,p) =>g.V().Has("name","stephenm"), (g,p) =>g.V().Has("name","stephenm").Properties<object>("name").Has("since",2010)}}, 
+               {"g_V_addVXanimalX_propertyXname_valuesXnameXX_propertyXname_an_animalX_propertyXvaluesXnameX_labelX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").AddV("software").Property(T.Id,5).Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property(T.Id,6).Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property(T.Id,7).Property("weight",0.5).AddE("knows").From("marko").To("josh").Property(T.Id,8).Property("weight",1.0).AddE("created").From("marko").To("lop").Property(T.Id,9).Property("weight",0.4).AddE("created").From("josh").To("ripple").Property(T.Id,10).Property("weight",1.0).AddE("created").From("josh").To("lop").Property(T.Id,11).Property("weight",0.4).AddE("created").From("peter").To("lop").Property(T.Id,12).Property("weight",0.2), (g,p) =>g.V().AddV("animal").Property("name",__.Values<object>("name")).Property("name","an animal").Property(__.Values<object>("name"),__.Label()), (g,p) =>g.V().HasLabel("animal").Has("name","marko").Has("name","an animal").Has("marko","person"), (g,p) =>g.V().HasLabel("animal").Has("name","vadas").Has("name","an animal").Has("vadas","person"), (g,p) =>g.V().HasLabel("animal").Has("name","lop").Has("name","an animal").Has("lop","software"), (g,p) =>g.V().HasLabel("animal").Has("name","josh").Has("name","an animal").Has("josh","person"), (g,p) =>g.V().HasLabel("animal").Has("name","ripple").Has("name","an animal").Has("ripple","software"), (g,p) =>g.V().HasLabel("animal").Has("name","peter").Has("name","an animal").Has("peter","person")}}, 
+               {"g_withSideEffectXa_testX_V_hasLabelXsoftwareX_propertyXtemp_selectXaXX_valueMapXname_tempX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").AddV("software").Property(T.Id,5).Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property(T.Id,6).Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property(T.Id,7).Property("weight",0.5).AddE("knows").From("marko").To("josh").Property(T.Id,8).Property("weight",1.0).AddE("created").From("marko").To("lop").Property(T.Id,9).Property("weight",0.4).AddE("created").From("josh").To("ripple").Property(T.Id,10).Property("weight",1.0).AddE("created").From("josh").To("lop").Property(T.Id,11).Property("weight",0.4).AddE("created").From("peter").To("lop").Property(T.Id,12).Property("weight",0.2), (g,p) =>g.WithSideEffect("a","test").V().HasLabel("software").Property("temp",__.Select<object>("a")).ValueMap<object,object>("name","temp")}}, 
+               {"g_withSideEffectXa_nameX_addV_propertyXselectXaX_markoX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").AddV("software").Property(T.Id,5).Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property(T.Id,6).Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property(T.Id,7).Property("weight",0.5).AddE("knows").From("marko").To("josh").Property(T.Id,8).Property("weight",1.0).AddE("created").From("marko").To("lop").Property(T.Id,9).Property("weight",0.4).AddE("created").From("josh").To("ripple").Property(T.Id,10).Property("weight",1.0).AddE("created").From("josh").To("lop").Property(T.Id,11).Property("weight",0.4).AddE("created").From("peter").To("lop").Property(T.Id,12).Property("weight",0.2), (g,p) =>g.WithSideEffect("a","name").AddV().Property(__.Select<object>("a"),"marko").Values<object>("name"), (g,p) =>g.V().Has("name","marko")}}, 
+               {"g_V_asXaX_hasXname_markoX_outXcreatedX_asXbX_addVXselectXaX_labelX_propertyXtest_selectXbX_labelX_valueMap_withXtokensX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").AddV("software").Property(T.Id,5).Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property(T.Id,6).Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property(T.Id,7).Property("weight",0.5).AddE("knows").From("marko").To("josh").Property(T.Id,8).Property("weight",1.0).AddE("created").From("marko").To("lop").Property(T.Id,9).Property("weight",0.4).AddE("created").From("josh").To("ripple").Property(T.Id,10).Property("weight",1.0).AddE("created").From("josh").To("lop").Property(T.Id,11).Property("weight",0.4).AddE("created").From("peter").To("lop").Property(T.Id,12).Property("weight",0.2), (g,p) =>g.V().As("a").Has("name","marko").Out("created").As("b").AddV(__.Select<object>("a").Label()).Property("test",__.Select<object>("b").Label()).ValueMap<object,object>().With("~tinkerpop.valueMap.tokens"), (g,p) =>g.V().Has("person","test","software")}}, 
+               {"g_addVXV_hasXname_markoX_propertiesXnameX_keyX_label", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").AddV("software").Property(T.Id,5).Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property(T.Id,6).Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property(T.Id,7).Property("weight",0.5).AddE("knows").From("marko").To("josh").Property(T.Id,8).Property("weight",1.0).AddE("created").From("marko").To("lop").Property(T.Id,9).Property("weight",0.4).AddE("created").From("josh").To("ripple").Property(T.Id,10).Property("weight",1.0).AddE("created").From("josh").To("lop").Property(T.Id,11).Property("weight",0.4).AddE("created").From("peter").To("lop").Property(T.Id,12).Property("weight",0.2), (g,p) =>g.AddV(__.V().Has("name","marko").Properties<object>("name").Key()).Label()}}, 
+               {"g_addVXnullX_propertyXid_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) null).Property(T.Id,null), (g,p) =>g.V().HasLabel("vertex")}}, 
+               {"g_addV_propertyXlabel_personX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV().Property(T.Label,"person"), (g,p) =>g.V().HasLabel("person")}}, 
+               {"g_V_coalesceXoutXfooX_outXbarXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Coalesce<object>(__.Out("foo"),__.Out("bar"))}}, 
+               {"g_VX1X_coalesceXoutXknowsX_outXcreatedXX_valuesXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Coalesce<object>(__.Out("knows"),__.Out("created")).Values<object>("name")}}, 
+               {"g_VX1X_coalesceXoutXcreatedX_outXknowsXX_valuesXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Coalesce<object>(__.Out("created"),__.Out("knows")).Values<object>("name")}}, 
+               {"g_V_coalesceXoutXlikesX_outXknowsX_inXcreatedXX_groupCount_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Coalesce<object>(__.Out("likes"),__.Out("knows"),__.Out("created")).GroupCount<object>().By("name")}}, 
+               {"g_V_coalesceXoutEXknowsX_outEXcreatedXX_otherV_path_byXnameX_byXlabelX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Coalesce<object>(__.OutE("knows"),__.OutE("created")).OtherV().Path().By("name").By(T.Label)}}, 
+               {"g_V_outXcreatedX_order_byXnameX_coalesceXname_constantXxXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Out("created").Order().By("name").Coalesce<object>(__.Values<object>("name"),__.Constant<object>("x"))}}, 
+               {"g_V_connectedComponent_hasXcomponentX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().ConnectedComponent().Has("gremlin.connectedComponentVertexProgram.component")}}, 
+               {"g_V_dedup_connectedComponent_hasXcomponentX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().Dedup().ConnectedComponent().Has("gremlin.connectedComponentVertexProgram.component")}}, 
+               {"g_V_hasLabelXsoftwareX_connectedComponent_project_byXnameX_byXcomponentX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().HasLabel("software").ConnectedComponent().Project<object>("name","component").By("name").By("gremlin.connectedComponentVertexProgram.component")}}, 
+               {"g_V_connectedComponent_withXEDGES_bothEXknowsXX_withXPROPERTY_NAME_clusterX_project_byXnameX_byXclusterX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().HasLabel("person").ConnectedComponent().With("~tinkerpop.connectedComponent.edges",__.BothE("knows")).With("~tinkerpop.connectedComponent.propertyName","cluster").Project<object>("name","cluster").By("name").By("cluster")}}, 
+               {"g_V_constantX123X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Constant<object>(123)}}, 
+               {"g_V_constantXnullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Constant<object>(null)}}, 
+               {"g_V_chooseXhasLabelXpersonX_valuesXnameX_constantXinhumanXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.HasLabel("person"),__.Values<object>("name"),__.Constant<object>("inhuman"))}}, 
+               {"g_V_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Count()}}, 
+               {"g_V_out_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Out().Count()}}, 
+               {"g_V_both_both_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Both().Both().Count()}}, 
+               {"g_V_fold_countXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Fold().Count(Scope.Local)}}, 
+               {"g_V_hasXnoX_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("no").Count()}}, 
+               {"g_V_whereXinXkknowsX_outXcreatedX_count_is_0XX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Where(__.In("knows").Out("created").Count().Is(0)).Values<object>("name")}}, 
+               {"g_V_repeatXoutX_timesX8X_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Repeat(__.Out()).Times(8).Count()}}, 
+               {"g_V_repeatXoutX_timesX5X_asXaX_outXwrittenByX_asXbX_selectXa_bX_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Repeat(__.Out()).Times(5).As("a").Out("writtenBy").As("b").Select<object>("a","b").Count()}}, 
+               {"g_V_repeatXoutX_timesX3X_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Repeat(__.Out()).Times(3).Count()}}, 
+               {"g_V_elementMap", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ElementMap<object>()}}, 
+               {"g_V_elementMapXname_ageX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ElementMap<object>("name","age")}}, 
+               {"g_EX11X_elementMap", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E(p["eid11"]).ElementMap<object>()}}, 
+               {"g_V_asXaX_flatMapXselectXaXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").FlatMap<object>(__.Select<object>("a"))}}, 
+               {"g_V_fold", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Fold()}}, 
+               {"g_V_fold_unfold", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Fold().Unfold<object>()}}, 
+               {"g_V_age_foldX0_plusX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Fold<object>(0,Operator.Sum)}}, 
+               {"g_VX1X_V_valuesXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).V().Values<object>("name")}}, 
+               {"g_V_outXknowsX_V_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Out("knows").V().Values<object>("name")}}, 
+               {"g_V_hasXname_GarciaX_inXsungByX_asXsongX_V_hasXname_Willie_DixonX_inXwrittenByX_whereXeqXsongXX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("artist","name","Garcia").In("sungBy").As("song").V().Has("artist","name","Willie_Dixon").In("writtenBy").Where(P.Eq("song")).Values<object>("name")}}, 
+               {"g_V_hasLabelXpersonX_asXpX_VXsoftwareX_addInEXuses_pX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").AddV("software").Property(T.Id,5).Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property(T.Id,6).Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property(T.Id,7).Property("weight",0.5).AddE("knows").From("marko").To("josh").Property(T.Id,8).Property("weight",1.0).AddE("created").From("marko").To("lop").Property(T.Id,9).Property("weight",0.4).AddE("created").From("josh").To("ripple").Property(T.Id,10).Property("weight",1.0).AddE("created").From("josh").To("lop").Property(T.Id,11).Property("weight",0.4).AddE("created").From("peter").To("lop").Property(T.Id,12).Property("weight",0.2), (g,p) =>g.V().HasLabel("person").As("p").V(p["xx1"]).AddE("uses").From("p"), (g,p) =>g.E().HasLabel("uses"), (g,p) =>g.V(p["vid1"]).OutE("uses"), (g,p) =>g.V(p["vid2"]).OutE("uses"), (g,p) =>g.V(p["vid3"]).InE("uses"), (g,p) =>g.V(p["vid4"]).OutE("uses"), (g,p) =>g.V(p["vid5"]).InE("uses"), (g,p) =>g.V(p["vid6"]).OutE("uses")}}, 
+               {"g_V_hasLabelXsoftwareX_index_unfold", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("software").Index<object>().Unfold<object>()}}, 
+               {"g_V_hasLabelXsoftwareX_order_byXnameX_index_withXmapX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("software").Order().By("name").Index<object>().With("~tinkerpop.index.indexer",1)}}, 
+               {"g_V_hasLabelXsoftwareX_name_fold_orderXlocalX_index_unfold_order_byXtailXlocal_1XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("software").Values<object>("name").Fold().Order(Scope.Local).Index<object>().Unfold<object>().Order().By(__.Tail<object>(Scope.Local,1))}}, 
+               {"g_V_hasLabelXpersonX_name_fold_orderXlocalX_index_withXmapX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Values<object>("name").Fold().Order(Scope.Local).Index<object>().With("~tinkerpop.index.indexer",1)}}, 
+               {"g_VX1X_repeatXboth_simplePathX_untilXhasXname_peterX_or_loops_isX3XX_hasXname_peterX_path_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Repeat(__.Both().SimplePath()).Until(__.Has("name","peter").Or().Loops().Is(3)).Has("name","peter").Path().By("name")}}, 
+               {"g_VX1X_repeatXboth_simplePathX_untilXhasXname_peterX_or_loops_isX2XX_hasXname_peterX_path_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Repeat(__.Both().SimplePath()).Until(__.Has("name","peter").Or().Loops().Is(2)).Has("name","peter").Path().By("name")}}, 
+               {"g_VX1X_repeatXboth_simplePathX_untilXhasXname_peterX_and_loops_isX3XX_hasXname_peterX_path_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Repeat(__.Both().SimplePath()).Until(__.Has("name","peter").And().Loops().Is(3)).Has("name","peter").Path().By("name")}}, 
+               {"g_V_emitXhasXname_markoX_or_loops_isX2XX_repeatXoutX_valuesXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Emit(__.Has("name","marko").Or().Loops().Is(2)).Repeat(__.Out()).Values<object>("name")}}, 
+               {"g_VX1X_mapXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Map<object>((IFunction) p["l1"])}}, 
+               {"g_VX1X_outE_label_mapXlengthX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).OutE().Label().Map<object>((IFunction) p["l1"])}}, 
+               {"g_VX1X_out_mapXnameX_mapXlengthX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out().Map<object>((IFunction) p["l1"]).Map<object>((IFunction) p["l2"])}}, 
+               {"g_VX1X_out_mapXlambdaXnameXX_mapXlambdaXlengthXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out().Map<object>(Lambda.Groovy("it.get().value(\'name\')")).Map<object>(Lambda.Groovy("it.get().toString().length()"))}}, 
+               {"g_withPath_V_asXaX_out_mapXa_nameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithPath().V().As("a").Out().Map<object>((IFunction) p["l1"])}}, 
+               {"g_withPath_V_asXaX_out_out_mapXa_name_it_nameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithPath().V().As("a").Out().Out().Map<object>((IFunction) p["l1"])}}, 
+               {"g_V_mapXselectXaXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Map<object>(__.Select<object>("a"))}}, 
+               {"g_V_mapXconstantXnullXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Map<object>(__.Constant<object>(null))}}, 
+               {"g_V_valueMap_matchXa_selectXnameX_bX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object,object>().Match<object>(__.As("a").Select<object>("name").As("b"))}}, 
+               {"g_V_matchXa_out_bX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Match<object>(__.As("a").Out().As("b"))}}, 
+               {"g_V_matchXa_out_bX_selectXb_idX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Match<object>(__.As("a").Out().As("b")).Select<object>("b").By(T.Id)}}, 
+               {"g_V_matchXa_knows_b__b_created_cX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Match<object>(__.As("a").Out("knows").As("b"),__.As("b").Out("created").As("c"))}}, 
+               {"g_V_matchXb_created_c__a_knows_bX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Match<object>(__.As("b").Out("created").As("c"),__.As("a").Out("knows").As("b"))}}, 
+               {"g_V_matchXa_created_b__b_0created_cX_whereXa_neq_cX_selectXa_cX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Match<object>(__.As("a").Out("created").As("b"),__.As("b").In("created").As("c")).Where("a",P.Neq("c")).Select<object>("a","c")}}, 
+               {"g_V_matchXd_0knows_a__d_hasXname_vadasX__a_knows_b__b_created_cX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Match<object>(__.As("d").In("knows").As("a"),__.As("d").Has("name","vadas"),__.As("a").Out("knows").As("b"),__.As("b").Out("created").As("c"))}}, 
+               {"g_V_matchXa_created_lop_b__b_0created_29_c__c_whereXrepeatXoutX_timesX2XXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Match<object>(__.As("a").Out("created").Has("name","lop").As("b"),__.As("b").In("created").Has("age",29).As("c"),__.As("c").Where(__.Repeat(__.Out()).Times(2)))}}, 
+               {"g_V_asXaX_out_asXbX_matchXa_out_count_c__b_in_count_cX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out().As("b").Match<object>(__.As("a").Out().Count().As("c"),__.As("b").In().Count().As("c"))}}, 
+               {"g_V_matchXa__a_out_b__notXa_created_bXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Match<object>(__.As("a").Out().As("b"),__.Not(__.As("a").Out("created").As("b")))}}, 
+               {"g_V_matchXa_created_lop_b__b_0created_29_cX_whereXc_repeatXoutX_timesX2XX_selectXa_b_cX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Match<object>(__.As("a").Out("created").Has("name","lop").As("b"),__.As("b").In("created").Has("age",29).As("c")).Where(__.As("c").Repeat(__.Out()).Times(2)).Select<object>("a","b","c")}}, 
+               {"g_V_out_out_matchXa_0created_b__b_0knows_cX_selectXcX_outXcreatedX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Out().Out().Match<object>(__.As("a").In("created").As("b"),__.As("b").In("knows").As("c")).Select<object>("c").Out("created").Values<object>("name")}}, 
+               {"g_V_matchXa_knows_b__b_created_c__a_created_cX_dedupXa_b_cX_selectXaX_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Match<object>(__.As("a").Out("knows").As("b"),__.As("b").Out("created").As("c"),__.As("a").Out("created").As("c")).Dedup("a","b","c").Select<object>("a").By("name")}}, 
+               {"g_V_matchXa_created_b__a_repeatXoutX_timesX2XX_selectXa_bX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Match<object>(__.As("a").Out("created").As("b"),__.As("a").Repeat(__.Out()).Times(2).As("b")).Select<object>("a","b")}}, 
+               {"g_V_notXmatchXa_age_b__a_name_cX_whereXb_eqXcXX_selectXaXX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Not(__.Match<object>(__.As("a").Values<object>("age").As("b"),__.As("a").Values<object>("name").As("c")).Where("b",P.Eq("c")).Select<object>("a")).Values<object>("name")}}, 
+               {"g_V_matchXa_knows_b__andXa_created_c__b_created_c__andXb_created_count_d__a_knows_count_dXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Match<object>(__.As("a").Out("knows").As("b"),__.And(__.As("a").Out("created").As("c"),__.As("b").Out("created").As("c"),__.And(__.As("b").Out("created").Count().As("d"),__.As("a").Out("knows").Count().As("d"))))}}, 
+               {"g_V_matchXa_whereXa_neqXcXX__a_created_b__orXa_knows_vadas__a_0knows_and_a_hasXlabel_personXX__b_0created_c__b_0created_count_isXgtX1XXX_selectXa_b_cX_byXidX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Match<object>(__.Where("a",P.Neq("c")),__.As("a").Out("created").As("b"),__.Or(__.As("a").Out("knows").Has("name","vadas"),__.As("a").In("knows").And().As("a").Has(T.Label,"person")),__.As("b").In("created").As("c"),__.As("b").In("created").Count().Is(P.Gt(1))).Select<object>("a","b","c").By(T.Id)}}, 
+               {"g_V_matchXa__a_both_b__b_both_cX_dedupXa_bX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Match<object>(__.As("a").Both().As("b"),__.As("b").Both().As("c")).Dedup("a","b")}}, 
+               {"g_V_matchXa_knows_b__b_created_lop__b_matchXb_created_d__d_0created_cX_selectXcX_cX_selectXa_b_cX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Match<object>(__.As("a").Out("knows").As("b"),__.As("b").Out("created").Has("name","lop"),__.As("b").Match<object>(__.As("b").Out("created").As("d"),__.As("d").In("created").As("c")).Select<object>("c").As("c")).Select<object>("a","b","c")}}, 
+               {"g_V_matchXa_knows_b__a_created_cX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Match<object>(__.As("a").Out("knows").As("b"),__.As("a").Out("created").As("c"))}}, 
+               {"g_V_matchXwhereXandXa_created_b__b_0created_count_isXeqX3XXXX__a_both_b__whereXb_inXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Match<object>(__.Where(__.And(__.As("a").Out("created").As("b"),__.As("b").In("created").Count().Is(P.Eq(3)))),__.As("a").Both().As("b"),__.Where(__.As("b").In()))}}, 
+               {"g_V_matchXa_outEXcreatedX_order_byXweight_descX_limitX1X_inV_b__b_hasXlang_javaXX_selectXa_bX_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Match<object>(__.As("a").OutE("created").Order().By("weight",Order.Desc).Limit<object>(1).InV().As("b"),__.As("b").Has("lang","java")).Select<object>("a","b").By("name")}}, 
+               {"g_V_matchXa_both_b__b_both_cX_dedupXa_bX_byXlabelX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Match<object>(__.As("a").Both().As("b"),__.As("b").Both().As("c")).Dedup("a","b").By(T.Label)}}, 
+               {"g_V_matchXa_created_b__b_0created_aX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Match<object>(__.As("a").Out("created").As("b"),__.As("b").In("created").As("a"))}}, 
+               {"g_V_asXaX_out_asXbX_matchXa_out_count_c__orXa_knows_b__b_in_count_c__and__c_isXgtX2XXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out().As("b").Match<object>(__.As("a").Out().Count().As("c"),__.Or(__.As("a").Out("knows").As("b"),__.As("b").In().Count().As("c").And().As("c").Is(P.Gt(2))))}}, 
+               {"g_V_matchXa_knows_count_bX_selectXbX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Match<object>(__.As("a").Out("knows").Count().As("b")).Select<object>("b")}}, 
+               {"g_V_matchXa_0sungBy_b__a_0writtenBy_c__b_writtenBy_d__c_sungBy_d__d_hasXname_GarciaXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Match<object>(__.As("a").In("sungBy").As("b"),__.As("a").In("writtenBy").As("c"),__.As("b").Out("writtenBy").As("d"),__.As("c").Out("sungBy").As("d"),__.As("d").Has("name","Garcia"))}}, 
+               {"g_V_matchXa_hasXsong_name_sunshineX__a_mapX0followedBy_weight_meanX_b__a_0followedBy_c__c_filterXweight_whereXgteXbXXX_outV_dX_selectXdX_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Match<object>(__.As("a").Has("song","name","HERE COMES SUNSHINE"),__.As("a").Map<object>(__.InE("followedBy").Values<object>("weight").Mean<object>()).As("b"),__.As("a").InE("followedBy").As("c"),__.As("c").Filter(__.Values<object>("weight").Where(P.Gte("b"))).OutV().As("d")).Select<object>("d").By("name")}}, 
+               {"g_V_matchXa_0sungBy_b__a_0sungBy_c__b_writtenBy_d__c_writtenBy_e__d_hasXname_George_HarisonX__e_hasXname_Bob_MarleyXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Match<object>(__.As("a").In("sungBy").As("b"),__.As("a").In("sungBy").As("c"),__.As("b").Out("writtenBy").As("d"),__.As("c").Out("writtenBy").As("e"),__.As("d").Has("name","George_Harrison"),__.As("e").Has("name","Bob_Marley"))}}, 
+               {"g_V_matchXa_hasXname_GarciaX__a_0writtenBy_b__a_0sungBy_bX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Match<object>(__.As("a").Has("name","Garcia"),__.As("a").In("writtenBy").As("b"),__.As("a").In("sungBy").As("b"))}}, 
+               {"g_V_hasLabelXsongsX_matchXa_name_b__a_performances_cX_selectXb_cX_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("song").Match<object>(__.As("a").Values<object>("name").As("b"),__.As("a").Values<object>("performances").As("c")).Select<object>("b","c").Count()}}, 
+               {"g_V_matchXa_followedBy_count_isXgtX10XX_b__a_0followedBy_count_isXgtX10XX_bX_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Match<object>(__.As("a").Out("followedBy").Count().Is(P.Gt(10)).As("b"),__.As("a").In("followedBy").Count().Is(P.Gt(10)).As("b")).Count()}}, 
+               {"g_V_matchXa_0sungBy_b__a_0writtenBy_c__b_writtenBy_dX_whereXc_sungBy_dX_whereXd_hasXname_GarciaXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Match<object>(__.As("a").In("sungBy").As("b"),__.As("a").In("writtenBy").As("c"),__.As("b").Out("writtenBy").As("d")).Where(__.As("c").Out("sungBy").As("d")).Where(__.As("d").Has("name","Garcia"))}}, 
+               {"g_V_matchXa_hasXname_GarciaX__a_0writtenBy_b__b_followedBy_c__c_writtenBy_d__whereXd_neqXaXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Match<object>(__.As("a").Has("name","Garcia"),__.As("a").In("writtenBy").As("b"),__.As("b").Out("followedBy").As("c"),__.As("c").Out("writtenBy").As("d"),__.Where("d",P.Neq("a")))}}, 
+               {"g_V_matchXa_outXknowsX_name_bX_identity", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Match<object>(__.As("a").Out("knows").Values<object>("name").As("b")).Identity()}}, 
+               {"g_V_outE_mathX0_minus_itX_byXweightX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().OutE().Math("0-_").By("weight")}}, 
+               {"g_V_hasXageX_valueMap_mathXit_plus_itXbyXselectXageX_unfoldXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age").ValueMap<object,object>().Math("_+_").By(__.Select<object>("age").Unfold<object>())}}, 
+               {"g_V_asXaX_outXknowsX_asXbX_mathXa_plus_bX_byXageX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out("knows").As("b").Math("a + b").By("age")}}, 
+               {"g_withSideEffectXx_100X_V_age_mathX__plus_xX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithSideEffect("x",p["xx1"]).V().Values<object>("age").Math("_ + x")}}, 
+               {"g_V_asXaX_outXcreatedX_asXbX_mathXb_plus_aX_byXinXcreatedX_countX_byXageX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out("created").As("b").Math("b + a").By(__.In("created").Count()).By("age")}}, 
+               {"g_withSackX1X_injectX1X_repeatXsackXsumX_byXconstantX1XXX_timesX5X_emit_mathXsin__X_byXsackX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithSack(1).Inject(1).Repeat(__.Sack(Operator.Sum).By(__.Constant<object>(1))).Times(5).Emit().Math("sin _").By(__.Sack<object>())}}, 
+               {"g_V_projectXa_b_cX_byXbothE_weight_sumX_byXbothE_countX_byXnameX_order_byXmathXa_div_bX_descX_selectXcX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Project<object>("a","b","c").By(__.BothE().Values<object>("weight").Sum<object>()).By(__.BothE().Count()).By("name").Order().By(__.Math("a / b"),Order.Desc).Select<object>("c")}}, 
+               {"g_V_age_max", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Max<object>()}}, 
+               {"g_V_foo_max", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("foo").Max<object>()}}, 
+               {"g_V_name_max", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Max<object>()}}, 
+               {"g_V_age_fold_maxXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Fold().Max<object>(Scope.Local)}}, 
+               {"g_V_foo_fold_maxXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("foo").Fold().Max<object>(Scope.Local)}}, 
+               {"g_V_name_fold_maxXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Fold().Max<object>(Scope.Local)}}, 
+               {"g_V_repeatXbothX_timesX5X_age_max", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Repeat(__.Both()).Times(5).Values<object>("age").Max<object>()}}, 
+               {"g_V_hasLabelXsoftwareX_group_byXnameX_byXbothE_weight_maxX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("software").Group<object,object>().By("name").By(__.BothE().Values<object>("weight").Max<object>())}}, 
+               {"g_V_age_mean", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Mean<object>()}}, 
+               {"g_V_foo_mean", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("foo").Mean<object>()}}, 
+               {"g_V_age_fold_meanXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Fold().Mean<object>(Scope.Local)}}, 
+               {"g_V_foo_fold_meanXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("foo").Fold().Mean<object>(Scope.Local)}}, 
+               {"g_V_hasLabelXsoftwareX_group_byXnameX_byXbothE_weight_meanX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("software").Group<object,object>().By("name").By(__.BothE().Values<object>("weight").Mean<object>())}}, 
+               {"g_V_age_min", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Min<object>()}}, 
+               {"g_V_foo_min", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("foo").Min<object>()}}, 
+               {"g_V_name_min", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Min<object>()}}, 
+               {"g_V_age_fold_minXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Fold().Min<object>(Scope.Local)}}, 
+               {"g_V_foo_fold_minXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("foo").Fold().Min<object>(Scope.Local)}}, 
+               {"g_V_name_fold_minXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Fold().Min<object>(Scope.Local)}}, 
+               {"g_V_repeatXbothX_timesX5X_age_min", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Repeat(__.Both()).Times(5).Values<object>("age").Min<object>()}}, 
+               {"g_V_hasLabelXsoftwareX_group_byXnameX_byXbothE_weight_minX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("software").Group<object,object>().By("name").By(__.BothE().Values<object>("weight").Min<object>())}}, 
+               {"g_V_foo_injectX9999999999X_min", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("foo").Inject(p["xx1"]).Min<object>()}}, 
+               {"g_V_name_order", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Order()}}, 
+               {"g_V_name_order_byXa1_b1X_byXb2_a2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Order().By((IComparator) p["c1"]).By((IComparator) p["c2"])}}, 
+               {"g_V_order_byXname_ascX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Order().By("name",Order.Asc).Values<object>("name")}}, 
+               {"g_V_order_byXnameX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Order().By("name").Values<object>("name")}}, 
+               {"g_V_outE_order_byXweight_descX_weight", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().OutE().Order().By("weight",Order.Desc).Values<object>("weight")}}, 
+               {"g_V_order_byXname_a1_b1X_byXname_b2_a2X_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Order().By("name",(IComparator) p["c1"]).By("name",(IComparator) p["c2"]).Values<object>("name")}}, 
+               {"g_V_asXaX_outXcreatedX_asXbX_order_byXshuffleX_selectXa_bX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out("created").As("b").Order().By(Order.Shuffle).Select<object>("a","b")}}, 
+               {"g_V_both_hasLabelXpersonX_order_byXage_descX_limitX5X_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Both().HasLabel("person").Order().By("age",Order.Desc).Limit<object>(5).Values<object>("name")}}, 
+               {"g_V_properties_order_byXkey_descX_key", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>().Order().By(T.Key,Order.Desc).Key()}}, 
+               {"g_V_hasLabelXpersonX_order_byXvalueXageX_descX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Order().By((IFunction) p["l1"],Order.Desc).Values<object>("name")}}, 
+               {"g_V_hasLabelXpersonX_group_byXnameX_byXoutE_weight_sumX_orderXlocalX_byXvaluesX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Group<object,object>().By("name").By(__.OutE().Values<object>("weight").Sum<object>()).Order(Scope.Local).By(Column.Values)}}, 
+               {"g_V_mapXbothE_weight_foldX_order_byXsumXlocalX_descX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Map<object>(__.BothE().Values<object>("weight").Fold()).Order().By(__.Sum<object>(Scope.Local),Order.Desc)}}, 
+               {"g_V_group_byXlabelX_byXname_order_byXdescX_foldX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Group<object,object>().By(T.Label).By(__.Values<object>("name").Order().By(Order.Desc).Fold())}}, 
+               {"g_V_hasLabelXpersonX_group_byXnameX_byXoutE_weight_sumX_unfold_order_byXvalues_descX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Group<object,object>().By("name").By(__.OutE().Values<object>("weight").Sum<object>()).Unfold<object>().Order().By(Column.Values,Order.Desc)}}, 
+               {"g_V_asXvX_mapXbothE_weight_foldX_sumXlocalX_asXsX_selectXv_sX_order_byXselectXsX_descX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("v").Map<object>(__.BothE().Values<object>("weight").Fold()).Sum<object>(Scope.Local).As("s").Select<object>("v","s").Order().By(__.Select<object>("s"),Order.Desc)}}, 
+               {"g_V_hasLabelXpersonX_fold_orderXlocalX_byXageX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Fold().Order(Scope.Local).By("age")}}, 
+               {"g_V_both_hasLabelXpersonX_order_byXage_descX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Both().HasLabel("person").Order().By("age",Order.Desc).Values<object>("name")}}, 
+               {"g_V_order_byXoutE_count_descX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Order().By(__.OutE().Count(),Order.Desc)}}, 
+               {"g_V_hasLabelXpersonX_order_byXageX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Order().By("age")}}, 
+               {"g_VX1X_hasXlabel_personX_mapXmapXint_ageXX_orderXlocalX_byXvalues_descX_byXkeys_ascX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V((Vertex) p["v1"]).HasLabel("person").Map<object>((IFunction) p["l1"]).Order(Scope.Local).By(Column.Values,Order.Desc).By(Column.Keys,Order.Asc)}}, 
+               {"g_VX1X_elementMap_orderXlocalX_byXkeys_descXunfold", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).ElementMap<object>().Order(Scope.Local).By(Column.Keys,Order.Desc).Unfold<object>()}}, 
+               {"g_V_pageRank_hasXpageRankX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().PageRank().Has("gremlin.pageRankVertexProgram.pageRank"), (g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().PageRank().Has("gremlin.pageRankVertexProgram.pageRank")}}, 
+               {"g_V_outXcreatedX_pageRank_withXedges_bothEX_withXpropertyName_projectRankX_withXtimes_0X_valueMapXname_projectRankX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().Out("created").PageRank().With("~tinkerpop.pageRank.edges",__.BothE()).With("~tinkerpop.pageRank.propertyName","projectRank").With("~tinkerpop.pageRank.times",0).ValueMap<object,object>("name","projectRank")}}, 
+               {"g_V_pageRank_order_byXpageRank_descX_byXnameX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().PageRank().Order().By("gremlin.pageRankVertexProgram.pageRank",Order.Desc).By("name").Values<object>("name")}}, 
+               {"g_V_pageRank_order_byXpageRank_descX_name_limitX2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().PageRank().Order().By("gremlin.pageRankVertexProgram.pageRank",Order.Desc).Values<object>("name").Limit<object>(2)}}, 
+               {"g_V_pageRank_withXedges_outEXknowsXX_withXpropertyName_friendRankX_project_byXnameX_byXvaluesXfriendRankX_mathX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().PageRank().With("~tinkerpop.pageRank.edges",__.OutE("knows")).With("~tinkerpop.pageRank.propertyName","friendRank").Project<object>("name","friendRank").By("name").By(__.Values<object>("friendRank").Math("ceil(_ * 100)"))}}, 
+               {"g_V_hasLabelXpersonX_pageRank_withXpropertyName_kpageRankX_project_byXnameX_byXvaluesXpageRankX_mathX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().HasLabel("person").PageRank().With("~tinkerpop.pageRank.propertyName","pageRank").Project<object>("name","pageRank").By("name").By(__.Values<object>("pageRank").Math("ceil(_ * 100)"))}}, 
+               {"g_V_pageRank_withXpropertyName_pageRankX_asXaX_outXknowsX_pageRank_asXbX_selectXa_bX_by_byXmathX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().PageRank().With("~tinkerpop.pageRank.propertyName","pageRank").As("a").Out("knows").Values<object>("pageRank").As("b").Select<object>("a","b").By().By(__.Math("ceil(_ * 100)"))}}, 
+               {"g_V_hasLabelXsoftwareX_hasXname_rippleX_pageRankX1X_withXedges_inEXcreatedX_withXtimes_1X_withXpropertyName_priorsX_inXcreatedX_unionXboth__identityX_valueMapXname_priorsX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().HasLabel("software").Has("name","ripple").PageRank(1.0).With("~tinkerpop.pageRank.edges",__.InE("created")).With("~tinkerpop.pageRank.times",1).With("~tinkerpop.pageRank.propertyName","priors").In("created").Union<object>(__.Both(),__.Identity()).ValueMap<object,object>("name","priors")}}, 
+               {"g_V_outXcreatedX_groupXmX_byXlabelX_pageRankX1X_withXpropertyName_pageRankX_withXedges_inEX_withXtimes_1X_inXcreatedX_groupXmX_byXpageRankX_capXmX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().Out("created").Group("m").By(T.Label).PageRank(1.0).With("~tinkerpop.pageRank.propertyName","pageRank").With("~tinkerpop.pageRank.edges",__.InE()).With("~tinkerpop.pageRank.times",1).In("created").Group("m").By("pageRank").Cap<object>("m")}}, 
+               {"g_VX1X_name_path", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Values<object>("name").Path()}}, 
+               {"g_VX1X_out_path_byXageX_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out().Path().By("age").By("name")}}, 
+               {"g_V_repeatXoutX_timesX2X_path_byXitX_byXnameX_byXlangX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Repeat(__.Out()).Times(2).Path().By().By("name").By("lang")}}, 
+               {"g_V_out_out_path_byXnameX_byXageX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Out().Out().Path().By("name").By("age")}}, 
+               {"g_V_asXaX_hasXname_markoX_asXbX_hasXage_29X_asXcX_path", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Has("name","marko").As("b").Has("age",29).As("c").Path()}}, 
+               {"g_VX1X_outEXcreatedX_inV_inE_outV_path", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).OutE("created").InV().InE().OutV().Path()}}, 
+               {"g_V_asXaX_out_asXbX_out_asXcX_path_fromXbX_toXcX_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out().As("b").Out().As("c").Path().From("b").To("c").By("name")}}, 
+               {"g_V_peerPressure_hasXclusterX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().PeerPressure().Has("gremlin.peerPressureVertexProgram.cluster"), (g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().PeerPressure().Has("gremlin.peerPressureVertexProgram.cluster")}}, 
+               {"g_V_peerPressure_withXpropertyName_clusterX_withXedges_outEXknowsXX_pageRankX1X_byXrankX_withXedges_outEXknowsX_withXtimes_2X_group_byXclusterX_byXrank_sumX_limitX100X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().PeerPressure().With("~tinkerpop.peerPressure.propertyName","cluster").With("~tinkerpop.peerPressure.edges",__.OutE("knows")).PageRank(1.0).With("~tinkerpop.pageRank.propertyName","rank").With("~tinkerpop.pageRank.edges",__.OutE("knows")).With("~tinkerpop.pageRank.times",1).Group<object,object>().By("cluster").By(__.Values<object>("rank").Sum<object>()).Limit<object>(100)}}, 
+               {"g_V_hasXname_rippleX_inXcreatedX_peerPressure_withXedges_outEX_withyXpropertyName_clusterX_repeatXunionXidentity__bothX_timesX2X_dedup_valueMapXname_clusterX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().Has("name","ripple").In("created").PeerPressure().With("~tinkerpop.peerPressure.edges",__.OutE()).With("~tinkerpop.peerPressure.propertyName","cluster").Repeat(__.Union<object>(__.Identity(),__.Both())).Times(2).Dedup().ValueMap<object,object>("name","cluster")}}, 
+               {"g_V_hasLabelXpersonX_projectXa_bX_byXoutE_countX_byXageX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Project<object>("a","b").By(__.OutE().Count()).By("age")}}, 
+               {"g_V_outXcreatedX_projectXa_bX_byXnameX_byXinXcreatedX_countX_order_byXselectXbX__descX_selectXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Out("created").Project<object>("a","b").By("name").By(__.In("created").Count()).Order().By(__.Select<object>("b"),Order.Desc).Select<object>("a")}}, 
+               {"g_V_valueMap_projectXxX_byXselectXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object,object>().Project<object>("x").By(__.Select<object>("name"))}}, 
+               {"g_V_hasXageX_propertiesXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age").Properties<object>("name").Value<object>()}}, 
+               {"g_V_hasXageX_propertiesXname_ageX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age").Properties<object>("name","age").Value<object>()}}, 
+               {"g_V_hasXageX_propertiesXage_nameX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age").Properties<object>("age","name").Value<object>()}}, 
+               {"get_g_VX1X_asXaX_outXknowsX_asXbX_selectXa_bX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).As("a").Out("knows").As("b").Select<object>("a","b")}}, 
+               {"g_VX1X_asXaX_outXknowsX_asXbX_selectXa_bX_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).As("a").Out("knows").As("b").Select<object>("a","b").By("name")}}, 
+               {"g_VX1X_asXaX_outXknowsX_asXbX_selectXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).As("a").Out("knows").As("b").Select<object>("a")}}, 
+               {"g_VX1X_asXaX_outXknowsX_asXbX_selectXaX_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).As("a").Out("knows").As("b").Select<object>("a").By("name")}}, 
+               {"g_V_asXaX_out_asXbX_selectXa_bX_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out().As("b").Select<object>("a","b").By("name")}}, 
+               {"g_V_asXaX_out_aggregateXxX_asXbX_selectXa_bX_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out().Aggregate("x").As("b").Select<object>("a","b").By("name")}}, 
+               {"g_V_asXaX_name_order_asXbX_selectXa_bX_byXnameX_by_XitX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Values<object>("name").Order().As("b").Select<object>("a","b").By("name").By()}}, 
+               {"g_V_hasXname_gremlinX_inEXusesX_order_byXskill_ascX_asXaX_outV_asXbX_selectXa_bX_byXskillX_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name","gremlin").InE("uses").Order().By("skill",Order.Asc).As("a").OutV().As("b").Select<object>("a","b").By("skill").By("name")}}, 
+               {"g_V_hasXname_isXmarkoXX_asXaX_selectXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name",__.Is("marko")).As("a").Select<object>("a")}}, 
+               {"g_V_label_groupCount_asXxX_selectXxX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Label().GroupCount<object>().As("x").Select<object>("x")}}, 
+               {"g_V_hasLabelXpersonX_asXpX_mapXbothE_label_groupCountX_asXrX_selectXp_rX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").As("p").Map<object>(__.BothE().Label().GroupCount<object>()).As("r").Select<object>("p","r")}}, 
+               {"g_V_chooseXoutE_count_isX0X__asXaX__asXbXX_chooseXselectXaX__selectXaX__selectXbXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.OutE().Count().Is(p["xx1"]),__.As("a"),__.As("b")).Choose<object>(__.Select<object>("a"),__.Select<object>("a"),__.Select<object>("b"))}}, 
+               {"g_VX1X_groupXaX_byXconstantXaXX_byXnameX_selectXaX_selectXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Group("a").By(__.Constant<object>("a")).By(__.Values<object>("name")).Barrier().Select<object>("a").Select<object>("a")}}, 
+               {"g_VX1X_asXhereX_out_selectXhereX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).As("here").Out().Select<object>("here")}}, 
+               {"g_VX4X_out_asXhereX_hasXlang_javaX_selectXhereX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid4"]).As("here").Out().Select<object>("here")}}, 
+               {"g_VX4X_out_asXhereX_hasXlang_javaX_selectXhereX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid4"]).Out().As("here").Has("lang","java").Select<object>("here").Values<object>("name")}}, 
+               {"g_VX1X_outE_asXhereX_inV_hasXname_vadasX_selectXhereX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).OutE().As("here").InV().Has("name","vadas").Select<object>("here")}}, 
+               {"g_VX1X_outEXknowsX_hasXweight_1X_asXhereX_inV_hasXname_joshX_selectXhereX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).OutE("knows").Has("weight",1.0).As("here").InV().Has("name","josh").Select<object>("here")}}, 
+               {"g_VX1X_outEXknowsX_asXhereX_hasXweight_1X_asXfakeX_inV_hasXname_joshX_selectXhereX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).OutE("knows").As("here").Has("weight",1.0).As("fake").InV().Has("name","josh").Select<object>("here")}}, 
+               {"g_V_asXhereXout_name_selectXhereX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("here").Out().Values<object>("name").Select<object>("here")}}, 
+               {"g_V_outXcreatedX_unionXasXprojectX_inXcreatedX_hasXname_markoX_selectXprojectX__asXprojectX_inXcreatedX_inXknowsX_hasXname_markoX_selectXprojectXX_groupCount_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Out("created").Union<object>(__.As("project").In("created").Has("name","marko").Select<object>("project"),__.As("project").In("created").In("knows").Has("name","marko").Select<object>("project")).GroupCount<object>().By("name")}}, 
+               {"g_V_untilXout_outX_repeatXin_asXaXX_selectXaX_byXtailXlocalX_nameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Until(__.Out().Out()).Repeat(__.In().As("a")).Select<object>("a").By(__.Tail<object>(Scope.Local).Values<object>("name"))}}, 
+               {"g_V_outE_weight_groupCount_selectXkeysX_unfold", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().OutE().Values<object>("weight").GroupCount<object>().Select<object>(Column.Keys).Unfold<object>()}}, 
+               {"g_V_hasLabelXsoftwareX_asXnameX_asXlanguageX_asXcreatorsX_selectXname_language_creatorsX_byXnameX_byXlangX_byXinXcreatedX_name_fold_orderXlocalXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("software").As("name").As("language").As("creators").Select<object>("name","language","creators").By("name").By("lang").By(__.In("created").Values<object>("name").Fold().Order(Scope.Local))}}, 
+               {"g_V_outE_weight_groupCount_unfold_selectXkeysX_unfold", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().OutE().Values<object>("weight").GroupCount<object>().Unfold<object>().Select<object>(Column.Keys).Unfold<object>()}}, 
+               {"g_V_outE_weight_groupCount_unfold_selectXvaluesX_unfold", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().OutE().Values<object>("weight").GroupCount<object>().Unfold<object>().Select<object>(Column.Values).Unfold<object>()}}, 
+               {"g_V_untilXout_outX_repeatXin_asXaX_in_asXbXX_selectXa_bX_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Until(__.Out().Out()).Repeat(__.In().As("a").In().As("b")).Select<object>("a","b").By("name")}}, 
+               {"g_V_outE_weight_groupCount_selectXvaluesX_unfold", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().OutE().Values<object>("weight").GroupCount<object>().Select<object>(Column.Values).Unfold<object>()}}, 
+               {"g_VX1X_asXaX_outXknowsX_asXbX_selectXa_bX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).As("a").Out("knows").As("b").Select<object>("a","b")}}, 
+               {"g_V_asXaX_whereXoutXknowsXX_selectXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Where(__.Out("knows")).Select<object>("a")}}, 
+               {"g_VX1X_asXaX_repeatXout_asXaXX_timesX2X_selectXfirst_aX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).As("a").Repeat(__.Out().As("a")).Times(2).Select<object>(Pop.First,"a")}}, 
+               {"g_V_asXaX_outXknowsX_asXbX_localXselectXa_bX_byXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out("knows").As("b").Local<object>(__.Select<object>("a","b").By("name"))}}, 
+               {"g_VX1X_asXaX_repeatXout_asXaXX_timesX2X_selectXlast_aX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).As("a").Repeat(__.Out().As("a")).Times(2).Select<object>(Pop.Last,"a")}}, 
+               {"g_VX1X_outEXknowsX_asXhereX_hasXweight_1X_inV_hasXname_joshX_selectXhereX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).OutE("knows").As("here").Has("weight",1.0).InV().Has("name","josh").Select<object>("here")}}, 
+               {"g_V_asXaX_hasXname_markoX_asXbX_asXcX_selectXa_b_cX_by_byXnameX_byXageX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Has("name","marko").As("b").As("c").Select<object>("a","b","c").By().By("name").By("age")}}, 
+               {"g_V_outE_weight_groupCount_selectXvaluesX_unfold_groupCount_selectXvaluesX_unfold", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().OutE().Values<object>("weight").GroupCount<object>().Select<object>(Column.Values).Unfold<object>().GroupCount<object>().Select<object>(Column.Values).Unfold<object>()}}, 
+               {"g_V_asXaX_groupXmX_by_byXbothE_countX_barrier_selectXmX_selectXselectXaXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Group("m").By().By(__.BothE().Count()).Barrier().Select<object>("m").Select<object>(__.Select<object>("a"))}}, 
+               {"g_V_asXaX_groupXmX_by_byXbothE_countX_barrier_selectXmX_selectXselectXaXX_byXmathX_plus_XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Group("m").By().By(__.BothE().Count()).Barrier().Select<object>("m").Select<object>(__.Select<object>("a")).By(__.Math("_+_"))}}, 
+               {"g_V_asXaX_outXknowsX_asXaX_selectXall_constantXaXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out("knows").As("a").Select<object>(Pop.All,__.Constant<object>("a"))}}, 
+               {"g_V_selectXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Select<object>("a")}}, 
+               {"g_V_selectXaX_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Select<object>("a").Count()}}, 
+               {"g_V_selectXa_bX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Select<object>("a","b")}}, 
+               {"g_V_valueMap_selectXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object,object>().Select<object>("a")}}, 
+               {"g_V_valueMap_selectXa_bX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object,object>().Select<object>("a","b")}}, 
+               {"g_V_selectXfirst_aX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Select<object>(Pop.First,"a")}}, 
+               {"g_V_selectXfirst_a_bX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Select<object>(Pop.First,"a","b")}}, 
+               {"g_V_valueMap_selectXfirst_aX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object,object>().Select<object>(Pop.First,"a")}}, 
+               {"g_V_valueMap_selectXfirst_a_bX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object,object>().Select<object>(Pop.First,"a","b")}}, 
+               {"g_V_selectXlast_aX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Select<object>(Pop.Last,"a")}}, 
+               {"g_V_selectXlast_a_bX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Select<object>(Pop.Last,"a","b")}}, 
+               {"g_V_valueMap_selectXlast_aX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object,object>().Select<object>(Pop.Last,"a")}}, 
+               {"g_V_valueMap_selectXlast_a_bX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object,object>().Select<object>(Pop.Last,"a","b")}}, 
+               {"g_V_selectXall_aX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Select<object>(Pop.All,"a")}}, 
+               {"g_V_selectXall_a_bX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Select<object>(Pop.All,"a","b")}}, 
+               {"g_V_valueMap_selectXall_aX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object,object>().Select<object>(Pop.All,"a")}}, 
+               {"g_V_valueMap_selectXall_a_bX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object,object>().Select<object>(Pop.All,"a","b")}}, 
+               {"g_V_asXa_bX_out_asXcX_path_selectXkeysX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a","b").Out().As("c").Path().Select<object>(Column.Keys), (g,p) =>g.V().As("a","b").Out().As("c").Path().Select<object>(Column.Keys)}}, 
+               {"g_V_hasXperson_name_markoX_barrier_asXaX_outXknows_selectXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("person","name","marko").Barrier().As("a").Out("knows").Select<object>("a")}}, 
+               {"g_V_hasXperson_name_markoX_elementMapXnameX_asXaX_unionXidentity_identityX_selectXaX_selectXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("person","name","marko").ElementMap<object>("name").As("a").Union<object>(__.Identity(),__.Identity()).Select<object>("a").Select<object>("name")}}, 
+               {"g_V_hasXperson_name_markoX_count_asXaX_unionXidentity_identityX_selectXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("person","name","marko").Count().As("a").Union<object>(__.Identity(),__.Identity()).Select<object>("a")}}, 
+               {"g_V_hasXperson_name_markoX_path_asXaX_unionXidentity_identityX_selectXaX_unfold", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("person","name","marko").Path().As("a").Union<object>(__.Identity(),__.Identity()).Select<object>("a").Unfold<object>()}}, 
+               {"g_EX11X_propertiesXweightX_asXaX_selectXaX_byXkeyX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E(p["eid11"]).Properties<object>("weight").As("a").Select<object>("a").By(T.Key)}}, 
+               {"g_EX11X_propertiesXweightX_asXaX_selectXaX_byXvalueX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E(p["eid11"]).Properties<object>("weight").As("a").Select<object>("a").By(T.Value)}}, 
+               {"g_V_shortestPath", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().Identity().ShortestPath()}}, 
+               {"g_V_both_dedup_shortestPath", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().Both().Dedup().ShortestPath()}}, 
+               {"g_V_shortestPath_edgesIncluded", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().Identity().ShortestPath().With("~tinkerpop.shortestPath.includeEdges")}}, 
+               {"g_V_shortestPath_directionXINX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().Identity().ShortestPath().With("~tinkerpop.shortestPath.edges",Direction.In)}}, 
+               {"g_V_shortestPath_edgesXoutEX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().Identity().ShortestPath().With("~tinkerpop.shortestPath.edges",__.OutE())}}, 
+               {"g_V_shortestPath_edgesIncluded_edgesXoutEX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().Identity().ShortestPath().With("~tinkerpop.shortestPath.includeEdges").With("~tinkerpop.shortestPath.edges",__.OutE())}}, 
+               {"g_V_hasXname_markoX_shortestPath", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().Has("name","marko").ShortestPath()}}, 
+               {"g_V_shortestPath_targetXhasXname_markoXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().Identity().ShortestPath().With("~tinkerpop.shortestPath.target",__.Has("name","marko"))}}, 
+               {"g_V_shortestPath_targetXvaluesXnameX_isXmarkoXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().Identity().ShortestPath().With("~tinkerpop.shortestPath.target",__.Values<object>("name").Is("marko"))}}, 
+               {"g_V_hasXname_markoX_shortestPath_targetXhasLabelXsoftwareXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().Has("name","marko").ShortestPath().With("~tinkerpop.shortestPath.target",__.HasLabel("software"))}}, 
+               {"g_V_hasXname_markoX_shortestPath_targetXhasXname_joshXX_distanceXweightX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().Has("name","marko").ShortestPath().With("~tinkerpop.shortestPath.target",__.Has("name","josh")).With("~tinkerpop.shortestPath.distance","weight")}}, 
+               {"g_V_hasXname_danielX_shortestPath_targetXhasXname_stephenXX_edgesXbothEXusesXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().Has("name","daniel").ShortestPath().With("~tinkerpop.shortestPath.target",__.Has("name","stephen")).With("~tinkerpop.shortestPath.edges",__.BothE("uses"))}}, 
+               {"g_V_hasXsong_name_MIGHT_AS_WELLX_shortestPath_targetXhasXsong_name_MAYBE_YOU_KNOW_HOW_I_FEELXX_edgesXoutEXfollowedByXX_distanceXweightX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().Has("song","name","MIGHT AS WELL").ShortestPath().With("~tinkerpop.shortestPath.target",__.Has("song","name","MAYBE YOU KNOW HOW I FEEL")).With("~tinkerpop.shortestPath.edges",__.OutE("followedBy")).With("~tinkerpop.shortestPath.distance","weight")}}, 
+               {"g_V_hasXname_markoX_shortestPath_maxDistanceX1X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().Has("name","marko").ShortestPath().With("~tinkerpop.shortestPath.maxDistance",1)}}, 
+               {"g_V_hasXname_vadasX_shortestPath_distanceXweightX_maxDistanceX1_3X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new VertexProgramStrategy(graphComputer: "org.apache.tinkerpop.gremlin.process.computer.GraphComputer")).V().Has("name","vadas").ShortestPath().With("~tinkerpop.shortestPath.distance","weight").With("~tinkerpop.shortestPath.maxDistance",1.3)}}, 
+               {"g_V_age_sum", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Sum<object>()}}, 
+               {"g_V_foo_sum", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("foo").Sum<object>()}}, 
+               {"g_V_age_fold_sumXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Fold().Sum<object>(Scope.Local)}}, 
+               {"g_V_foo_fold_sumXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("foo").Fold().Sum<object>(Scope.Local)}}, 
+               {"g_V_hasLabelXsoftwareX_group_byXnameX_byXbothE_weight_sumX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("software").Group<object,object>().By("name").By(__.BothE().Values<object>("weight").Sum<object>())}}, 
+               {"g_V_localXoutE_foldX_unfold", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Local<object>(__.OutE().Fold()).Unfold<object>()}}, 
+               {"g_V_valueMap_unfold_mapXkeyX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object,object>().Unfold<object>().Map<object>((IFunction) p["l1"])}}, 
+               {"g_VX1X_repeatXboth_simplePathX_untilXhasIdX6XX_path_byXnameX_unfold", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Repeat(__.Both().SimplePath()).Until(__.HasId(p["vid6"])).Path().By("name").Unfold<object>()}}, 
+               {"g_V_valueMap", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object,object>()}}, 
+               {"g_V_valueMapXtrueX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object,object>(true)}}, 
+               {"g_V_valueMap_withXtokensX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object,object>().With("~tinkerpop.valueMap.tokens")}}, 
+               {"g_V_valueMapXname_ageX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object,object>("name","age")}}, 
+               {"g_V_valueMapXtrue_name_ageX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object,object>(true,"name","age")}}, 
+               {"g_V_valueMapXname_ageX_withXtokensX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object,object>("name","age").With("~tinkerpop.valueMap.tokens")}}, 
+               {"g_V_valueMapXname_ageX_withXtokens_labelsX_byXunfoldX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object,object>("name","age").With("~tinkerpop.valueMap.tokens",2).By(__.Unfold<object>())}}, 
+               {"g_V_valueMapXname_ageX_withXtokens_idsX_byXunfoldX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object,object>("name","age").With("~tinkerpop.valueMap.tokens",1).By(__.Unfold<object>())}}, 
+               {"g_VX1X_outXcreatedX_valueMap", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out("created").ValueMap<object,object>()}}, 
+               {"g_V_hasLabelXpersonX_filterXoutEXcreatedXX_valueMapXtrueX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Filter(__.OutE("created")).ValueMap<object,object>(true)}}, 
+               {"g_V_hasLabelXpersonX_filterXoutEXcreatedXX_valueMap_withXtokensX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Filter(__.OutE("created")).ValueMap<object,object>().With("~tinkerpop.valueMap.tokens")}}, 
+               {"g_VX1X_valueMapXname_locationX_byXunfoldX_by", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).ValueMap<object,object>("name","location").By(__.Unfold<object>()).By()}}, 
+               {"g_VXlistX1_2_3XX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["xx1"]).Values<object>("name")}}, 
+               {"g_VXlistXv1_v2_v3XX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["xx1"]).Values<object>("name")}}, 
+               {"g_V", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V()}}, 
+               {"g_VXv1X_out", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V((Vertex) p["v1"]).Out()}}, 
+               {"g_VX1X_out", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out()}}, 
+               {"g_VX2X_in", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid2"]).In()}}, 
+               {"g_VX4X_both", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid4"]).Both()}}, 
+               {"g_E", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E()}}, 
+               {"g_EX11X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E(p["eid11"])}}, 
+               {"g_EX11AsStringX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E(p["eid11"])}}, 
+               {"g_EXe11X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E(p["e11"])}}, 
+               {"g_EXe7_e11X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E(p["e7"],p["e11"])}}, 
+               {"g_EXlistXe7_e11XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E(p["xx1"])}}, 
+               {"g_VX1X_outE", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).OutE()}}, 
+               {"g_VX2X_outE", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid2"]).InE()}}, 
+               {"g_VX4X_bothEXcreatedX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid4"]).BothE("created")}}, 
+               {"g_VX4X_bothE", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid4"]).BothE()}}, 
+               {"g_VX1X_outE_inV", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Both()}}, 
+               {"g_VX2X_inE_outV", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid2"]).InE().OutV()}}, 
+               {"g_V_outE_hasXweight_1X_outV", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().OutE().Has("weight",1.0).OutV()}}, 
+               {"g_V_out_outE_inV_inE_inV_both_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Out().OutE().InV().InE().InV().Both().Values<object>("name")}}, 
+               {"g_VX1X_outEXknowsX_bothV_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).OutE("knows").BothV().Values<object>("name")}}, 
+               {"g_VX1X_outE_otherV", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).OutE().OtherV()}}, 
+               {"g_VX4X_bothE_otherV", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid4"]).BothE().OtherV()}}, 
+               {"g_VX4X_bothE_hasXweight_lt_1X_otherV", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid4"]).BothE().Has("weight",P.Lt(1.0)).OtherV()}}, 
+               {"g_VX2X_inE", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid2"]).BothE()}}, 
+               {"get_g_VX1X_outE_otherV", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).OutE().OtherV()}}, 
+               {"g_VX1X_outXknowsX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out("knows")}}, 
+               {"g_VX1AsStringX_outXknowsX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out("knows")}}, 
+               {"g_VX1X_outXknows_createdX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out("knows","created")}}, 
+               {"g_VX1X_outEXknowsX_inV", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).OutE("knows").InV()}}, 
+               {"g_VX1X_outEXknows_createdX_inV", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).OutE("knows","created").InV()}}, 
+               {"g_V_out_out", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Out().Out()}}, 
+               {"g_VX1X_out_out_out", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out().Out().Out()}}, 
+               {"g_VX1X_out_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out().Values<object>("name")}}, 
+               {"g_VX1X_to_XOUT_knowsX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).To(Direction.Out,"knows")}}, 
+               {"g_VX1_2_3_4X_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"],p["vid2"],p["vid3"],p["vid4"]).Values<object>("name")}}, 
+               {"g_V_hasLabelXpersonX_V_hasLabelXsoftwareX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").V().HasLabel("software").Values<object>("name")}}, 
+               {"g_V_hasLabelXloopsX_bothEXselfX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("loops").BothE("self")}}, 
+               {"g_V_hasLabelXloopsX_bothXselfX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("loops").Both("self")}}, 
+               {"g_V_valueXnameX_aggregateXxX_capXxX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Aggregate("x").Cap<object>("x")}}, 
+               {"g_V_valueXnameX_aggregateXglobal_xX_capXxX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Aggregate(Scope.Global,"x").Cap<object>("x")}}, 
+               {"g_V_aggregateXxX_byXnameX_capXxX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Aggregate("x").By("name").Cap<object>("x")}}, 
+               {"g_V_out_aggregateXaX_path", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Out().Aggregate("a").Path()}}, 
+               {"g_V_hasLabelXpersonX_aggregateXxX_byXageX_capXxX_asXyX_selectXyX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Aggregate("x").By("age").Cap<object>("x").As("y").Select<object>("y")}}, 
+               {"g_V_aggregateXlocal_a_nameX_out_capXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Aggregate(Scope.Local,"a").By("name").Out().Cap<object>("a")}}, 
+               {"g_VX1X_aggregateXlocal_aX_byXnameX_out_aggregateXlocal_aX_byXnameX_name_capXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Aggregate(Scope.Local,"a").By("name").Out().Aggregate(Scope.Local,"a").By("name").Values<object>("name").Cap<object>("a")}}, 
+               {"g_withSideEffectXa_setX_V_both_name_aggregateXlocal_aX_capXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithSideEffect("a",p["xx1"]).V().Both().Values<object>("name").Aggregate(Scope.Local,"a").Cap<object>("a")}}, 
+               {"g_V_aggregateXlocal_aX_byXoutEXcreatedX_countX_out_out_aggregateXlocal_aX_byXinEXcreatedX_weight_sumX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Aggregate(Scope.Local,"a").By(__.OutE("created").Count()).Out().Out().Aggregate(Scope.Local,"a").By(__.InE("created").Values<object>("weight").Sum<object>()).Cap<object>("a")}}, 
+               {"g_V_group_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Group<object,object>().By("name")}}, 
+               {"g_V_group_byXageX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Group<object,object>().By("age")}}, 
+               {"g_V_group_byXnameX_by", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Group<object,object>().By("name").By()}}, 
+               {"g_V_groupXaX_byXnameX_capXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Group("a").By("name").Cap<object>("a")}}, 
+               {"g_V_hasXlangX_groupXaX_byXlangX_byXnameX_out_capXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("lang").Group("a").By("lang").By("name").Out().Cap<object>("a")}}, 
+               {"g_V_hasXlangX_group_byXlangX_byXcountX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("lang").Group<object,object>().By("lang").By(__.Count())}}, 
+               {"g_V_repeatXout_groupXaX_byXnameX_byXcountX_timesX2X_capXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Repeat(__.Out().Group("a").By("name").By(__.Count())).Times(2).Cap<object>("a")}}, 
+               {"g_V_group_byXoutE_countX_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Group<object,object>().By(__.OutE().Count()).By("name")}}, 
+               {"g_V_groupXaX_byXlabelX_byXoutE_weight_sumX_capXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Group("a").By(T.Label).By(__.OutE().Values<object>("weight").Sum<object>()).Cap<object>("a")}}, 
+               {"g_V_repeatXbothXfollowedByXX_timesX2X_group_byXsongTypeX_byXcountX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Repeat(__.Both("followedBy")).Times(2).Group<object,object>().By("songType").By(__.Count())}}, 
+               {"g_V_repeatXbothXfollowedByXX_timesX2X_groupXaX_byXsongTypeX_byXcountX_capXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Repeat(__.Both("followedBy")).Times(2).Group("a").By("songType").By(__.Count()).Cap<object>("a")}}, 
+               {"g_V_group_byXname_substring_1X_byXconstantX1XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Group<object,object>().By((IFunction) p["l1"]).By(__.Constant<object>(1))}}, 
+               {"g_V_groupXaX_byXname_substring_1X_byXconstantX1XX_capXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Group("a").By((IFunction) p["l1"]).By(__.Constant<object>(1)).Cap<object>("a")}}, 
+               {"g_V_out_group_byXlabelX_selectXpersonX_unfold_outXcreatedX_name_limitX2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Out().Group<object,object>().By(T.Label).Select<object>("person").Unfold<object>().Out("created").Values<object>("name").Limit<object>(2)}}, 
+               {"g_V_hasLabelXsongX_group_byXnameX_byXproperties_groupCount_byXlabelXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("song").Group<object,object>().By("name").By(__.Properties<object>().GroupCount<object>().By(T.Label))}}, 
+               {"g_V_hasLabelXsongX_groupXaX_byXnameX_byXproperties_groupCount_byXlabelXX_out_capXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("song").Group("a").By("name").By(__.Properties<object>().GroupCount<object>().By(T.Label)).Out().Cap<object>("a")}}, 
+               {"g_V_outXfollowedByX_group_byXsongTypeX_byXbothE_group_byXlabelX_byXweight_sumXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Out("followedBy").Group<object,object>().By("songType").By(__.BothE().Group<object,object>().By(T.Label).By(__.Values<object>("weight").Sum<object>()))}}, 
+               {"g_V_groupXmX_byXnameX_byXinXknowsX_nameX_capXmX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Group("m").By("name").By(__.In("knows").Values<object>("name")).Cap<object>("m")}}, 
+               {"g_V_group_byXlabelX_byXbothE_groupXaX_byXlabelX_byXweight_sumX_weight_sumX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Group<object,object>().By(T.Label).By(__.BothE().Group("a").By(T.Label).By(__.Values<object>("weight").Sum<object>()).Values<object>("weight").Sum<object>())}}, 
+               {"g_withSideEffectXa__marko_666_noone_blahX_V_groupXaX_byXnameX_byXoutE_label_foldX_capXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithSideEffect("a",p["xx1"]).V().Group("a").By("name").By(__.OutE().Label().Fold()).Cap<object>("a")}}, 
+               {"g_V_hasLabelXpersonX_asXpX_outXcreatedX_group_byXnameX_byXselectXpX_valuesXageX_sumX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").As("p").Out("created").Group<object,object>().By("name").By(__.Select<object>("p").Values<object>("age").Sum<object>())}}, 
+               {"g_V_hasLabelXpersonX_asXpX_outXcreatedX_groupXaX_byXnameX_byXselectXpX_valuesXageX_sumX_capXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").As("p").Out("created").Group("a").By("name").By(__.Select<object>("p").Values<object>("age").Sum<object>()).Cap<object>("a")}}, 
+               {"g_V_group_byXlabelX_byXlabel_countX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Group<object,object>().By(__.Label()).By(__.Label().Count())}}, 
+               {"g_V_groupXmX_byXlabelX_byXlabel_countX_capXmX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Group("m").By(__.Label()).By(__.Label().Count()).Cap<object>("m")}}, 
+               {"g_V_outXcreatedX_groupCount_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Out("created").GroupCount<object>().By("name")}}, 
+               {"g_V_outXcreatedX_name_groupCount", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Out("created").Values<object>("name").GroupCount<object>()}}, 
+               {"g_V_outXcreatedX_groupCountXaX_byXnameX_capXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Out("created").GroupCount("a").By("name").Cap<object>("a")}}, 
+               {"g_V_outXcreatedX_name_groupCountXaX_capXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Out("created").Values<object>("name").GroupCount("a").Cap<object>("a")}}, 
+               {"g_V_repeatXout_groupCountXaX_byXnameXX_timesX2X_capXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Repeat(__.Out().GroupCount("a").By("name")).Times(2).Cap<object>("a")}}, 
+               {"g_V_both_groupCountXaX_byXlabelX_asXbX_barrier_whereXselectXaX_selectXsoftwareX_isXgtX2XXX_selectXbX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Both().GroupCount("a").By(T.Label).As("b").Barrier().Where(__.Select<object>("a").Select<object>("software").Is(P.Gt(2))).Select<object>("b").Values<object>("name")}}, 
+               {"g_V_unionXoutXknowsX__outXcreatedX_inXcreatedXX_groupCount_selectXvaluesX_unfold_sum", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Union<object>(__.Out("knows"),__.Out("created").In("created")).GroupCount<object>().Select<object>(Column.Values).Unfold<object>().Sum<object>()}}, 
+               {"g_V_hasXnoX_groupCount", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("no").GroupCount<object>()}}, 
+               {"g_V_hasXnoX_groupCountXaX_capXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("no").GroupCount("a").Cap<object>("a")}}, 
+               {"g_V_unionXrepeatXoutX_timesX2X_groupCountXmX_byXlangXX__repeatXinX_timesX2X_groupCountXmX_byXnameXX_capXmX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Union<object>(__.Repeat(__.Out()).Times(2).GroupCount("m").By("lang"),__.Repeat(__.In()).Times(2).GroupCount("m").By("name")).Cap<object>("m")}}, 
+               {"g_V_outXcreatedX_groupCountXxX_capXxX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Out("created").GroupCount("x").Cap<object>("x")}}, 
+               {"g_V_groupCount_byXbothE_countX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().GroupCount<object>().By(__.BothE().Count())}}, 
+               {"g_V_both_groupCountXaX_out_capXaX_selectXkeysX_unfold_both_groupCountXaX_capXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Both().GroupCount("a").Out().Cap<object>("a").Select<object>(Column.Keys).Unfold<object>().Both().GroupCount("a").Cap<object>("a")}}, 
+               {"g_V_hasXperson_name_markoX_bothXknowsX_groupCount_byXvaluesXnameX_foldX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("person","name","marko").Both("knows").GroupCount<object>().By(__.Values<object>("name").Fold())}}, 
+               {"g_VX1X_out_injectXv2X_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out().Inject((Vertex) p["v2"]).Values<object>("name")}}, 
+               {"g_VX1X_out_name_injectXdanielX_asXaX_mapXlengthX_path", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out().Values<object>("name").Inject("daniel").As("a").Map<object>((IFunction) p["l1"]).Path()}}, 
+               {"g_VX1X_injectXg_VX4XX_out_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Inject((Vertex) p["v4"]).Out().Values<object>("name")}}, 
+               {"g_injectXnull_1_3_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(null,1,3,null)}}, 
+               {"g_injectX10_20_null_20_10_10X_groupCountXxX_dedup_asXyX_projectXa_bX_by_byXselectXxX_selectXselectXyXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(10,20,null,20,10,10).GroupCount("x").Dedup().As("y").Project<object>("a","b").By().By(__.Select<object>("x").Select<object>(__.Select<object>("y")))}}, 
+               {"g_injectXname_marko_age_nullX_selectXname_ageX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(p["xx1"]).Select<object>("name","age")}}, 
+               {"g_io_readXkryoX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Io<object>("data/tinkerpop-modern.kryo").Read(), (g,p) =>g.V(), (g,p) =>g.E()}}, 
+               {"g_io_read_withXreader_gryoX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Io<object>("data/tinkerpop-modern.kryo").With("~tinkerpop.io.reader","gryo").Read(), (g,p) =>g.V(), (g,p) =>g.E()}}, 
+               {"g_io_readXgraphsonX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Io<object>("data/tinkerpop-modern.json").Read(), (g,p) =>g.V(), (g,p) =>g.E()}}, 
+               {"g_io_read_withXreader_graphsonX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Io<object>("data/tinkerpop-modern.json").With("~tinkerpop.io.reader","graphson").Read(), (g,p) =>g.V(), (g,p) =>g.E()}}, 
+               {"g_io_readXgraphmlX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Io<object>("data/tinkerpop-modern.xml").Read(), (g,p) =>g.V(), (g,p) =>g.E()}}, 
+               {"g_io_read_withXreader_graphmlX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Io<object>("data/tinkerpop-modern.xml").With("~tinkerpop.io.reader","graphml").Read(), (g,p) =>g.V(), (g,p) =>g.E()}}, 
+               {"g_withSackXhelloX_V_outE_sackXassignX_byXlabelX_inV_sack", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithSack("hello").V().OutE().Sack(Operator.Assign).By(T.Label).InV().Sack<object>()}}, 
+               {"g_withSackX0X_V_outE_sackXsumX_byXweightX_inV_sack_sum", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithSack(0.0).V().OutE().Sack(Operator.Sum).By("weight").InV().Sack<object>().Sum<object>()}}, 
+               {"g_withSackX0X_V_repeatXoutE_sackXsumX_byXweightX_inVX_timesX2X_sack", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithSack(0.0).V().Repeat(__.OutE().Sack(Operator.Sum).By("weight").InV()).Times(2).Sack<object>()}}, 
+               {"g_withBulkXfalseX_withSackX1_sumX_VX1X_localXoutEXknowsX_barrierXnormSackX_inVX_inXknowsX_barrier_sack", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithBulk(false).WithSack(1.0,Operator.Sum).V(p["vid1"]).Local<object>(__.OutE("knows").Barrier(Barrier.NormSack).InV()).In("knows").Barrier().Sack<object>()}}, 
+               {"g_withBulkXfalseX_withSackX1_sumX_V_out_barrier_sack", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithBulk(false).WithSack(1,Operator.Sum).V().Out().Barrier().Sack<object>()}}, 
+               {"g_withSackX1_sumX_VX1X_localXoutXknowsX_barrierXnormSackXX_inXknowsX_barrier_sack", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithSack(1.0,Operator.Sum).V(p["vid1"]).Local<object>(__.Out("knows").Barrier(Barrier.NormSack)).In("knows").Barrier().Sack<object>()}}, 
+               {"g_V_hasXageX_groupCountXaX_byXnameX_out_capXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age").GroupCount("a").By("name").Out().Cap<object>("a")}}, 
+               {"g_V_storeXa_nameX_out_capXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Store("a").By("name").Out().Cap<object>("a")}}, 
+               {"g_VX1X_storeXaX_byXnameX_out_storeXaX_byXnameX_name_capXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Store("a").By("name").Out().Store("a").By("name").Values<object>("name").Cap<object>("a")}}, 
+               {"g_withSideEffectXa_setX_V_both_name_storeXaX_capXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithSideEffect("a",p["xx1"]).V().Both().Values<object>("name").Store("a").Cap<object>("a")}}, 
+               {"g_V_storeXaX_byXoutEXcreatedX_countX_out_out_storeXaX_byXinEXcreatedX_weight_sumX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Store("a").By(__.OutE("created").Count()).Out().Out().Store("a").By(__.InE("created").Values<object>("weight").Sum<object>()).Cap<object>("a")}}, 
+            };
+
+        public static ITraversal UseTraversal(string scenarioName, GraphTraversalSource g, IDictionary<string, object> parameters)
+        {
+            List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> list = _translationsForTestRun[scenarioName];
+            Func<GraphTraversalSource, IDictionary<string, object>, ITraversal> f = list[0];
+            list.RemoveAt(0);
+            return f.Invoke(g, parameters);
+        }
+    }
+}
+
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/IgnoreException.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/IgnoreException.cs
index 726e684..9579626 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/IgnoreException.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/IgnoreException.cs
@@ -50,12 +50,16 @@
     
     public enum IgnoreReason
     {
-        /// <summary>
-        /// Deserialization of g:T on GraphSON3 is not supported.
-        /// </summary>
-        TraversalTDeserializationNotSupported,
-        ReceivedDataDoesntMatchExpected,
         NoReason,
-        EmbeddedListAssertion
+
+        /// <summary>
+        /// C# does not allow a `null` value to be used as a key.
+        /// </summary>
+        NullKeysInMapNotSupported,
+        
+        /// <summary>
+        /// C# array equality is by reference not contents so the gherkin setup won't assert properly
+        /// </summary>
+        ArrayKeysInMapNotAssertingInGherkin
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/ScenarioData.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/ScenarioData.cs
index 8c80982..e669e60 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/ScenarioData.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/ScenarioData.cs
@@ -25,6 +25,8 @@
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Linq;
+using Gherkin.Ast;
+using Gremlin.Net.Driver;
 using Gremlin.Net.Driver.Exceptions;
 using Gremlin.Net.IntegrationTest.Process.Traversal.DriverRemoteConnection;
 using Gremlin.Net.Process.Remote;
@@ -35,10 +37,8 @@
 
 namespace Gremlin.Net.IntegrationTest.Gherkin
 {
-    internal class ScenarioData
+    internal class ScenarioData : IDisposable
     {
-        private static readonly Lazy<ScenarioData> Lazy = new Lazy<ScenarioData>(Load);
-        
         private static readonly string[] GraphNames = {"modern", "classic", "crew", "grateful", "sink"};
 
         private static readonly IDictionary<string, Vertex> EmptyVertices =
@@ -47,36 +47,32 @@
         private static readonly IDictionary<string, Edge> EmptyEdges =
             new ReadOnlyDictionary<string, Edge>(new Dictionary<string, Edge>());
         
-        private static readonly RemoteConnectionFactory ConnectionFactory = new RemoteConnectionFactory();
+        private readonly RemoteConnectionFactory _connectionFactory;
 
-        public static ScenarioDataPerGraph GetByGraphName(string name)
+        public ScenarioDefinition CurrentScenario;
+
+        public ScenarioDataPerGraph GetByGraphName(string name)
         {
             if (name == null)
             {
                 throw new ArgumentNullException(nameof(name), "Graph name can not be empty");
             }
-            var dataPerGraph = Lazy.Value._dataPerGraph;
-            if (!dataPerGraph.TryGetValue(name, out var data))
+            if (!_dataPerGraph.TryGetValue(name, out var data))
             {
                 throw new KeyNotFoundException($"Graph data with key '{name}' not found");
             }
             return data;
         }
 
-        public static void Shutdown()
-        {
-            ConnectionFactory.Dispose();
-        }
-
-        public static void CleanEmptyData()
+        public void CleanEmptyData()
         {
             var g = Traversal().WithRemote(GetByGraphName("empty").Connection);
             g.V().Drop().Iterate();
         }
 
-        public static void ReloadEmptyData()
+        public void ReloadEmptyData()
         {
-            var graphData = Lazy.Value._dataPerGraph["empty"];
+            var graphData = _dataPerGraph["empty"];
             var g = Traversal().WithRemote(graphData.Connection);
             graphData.Vertices = GetVertices(g);
             graphData.Edges = GetEdges(g);
@@ -84,34 +80,35 @@
 
         private readonly IDictionary<string, ScenarioDataPerGraph> _dataPerGraph;
         
-        private ScenarioData(IDictionary<string, ScenarioDataPerGraph> dataPerGraph)
+        public ScenarioData(IMessageSerializer messageSerializer)
         {
-            _dataPerGraph = new Dictionary<string, ScenarioDataPerGraph>(dataPerGraph);
-            var empty = new ScenarioDataPerGraph("empty", ConnectionFactory.CreateRemoteConnection("ggraph"),
+            _connectionFactory = new RemoteConnectionFactory(messageSerializer);
+            _dataPerGraph = LoadDataPerGraph();
+            var empty = new ScenarioDataPerGraph("empty", _connectionFactory.CreateRemoteConnection("ggraph"),
                 new Dictionary<string, Vertex>(0), new Dictionary<string, Edge>());
             _dataPerGraph.Add("empty", empty);
         }
 
-        private static ScenarioData Load()
+        private Dictionary<string, ScenarioDataPerGraph> LoadDataPerGraph()
         {
-            return new ScenarioData(GraphNames.Select(name =>
+            return GraphNames.Select(name =>
             {
-                var connection = ConnectionFactory.CreateRemoteConnection($"g{name}");
+                var connection = _connectionFactory.CreateRemoteConnection($"g{name}");
                 var g = Traversal().WithRemote(connection);
                 return new ScenarioDataPerGraph(name, connection, GetVertices(g), GetEdges(g));
-            }).ToDictionary(x => x.Name));
+            }).ToDictionary(x => x.Name);
         }
 
         private static IDictionary<string, Vertex> GetVertices(GraphTraversalSource g)
         {
-            try
+            // Property name might not exist and C# doesn't support "null" keys in Dictionary
+            if (g.V().Count().Next() == g.V().Has("name").Count().Next())
             {
                 return g.V().Group<string, object>().By("name").By(__.Tail<Vertex>()).Next()
                     .ToDictionary(kv => kv.Key, kv => (Vertex) kv.Value);
             }
-            catch (ResponseException)
+            else
             {
-                // Property name might not exist
                 return EmptyVertices;
             }
         }
@@ -134,6 +131,11 @@
                 return EmptyEdges;
             }
         }
+
+        public void Dispose()
+        {
+            _connectionFactory?.Dispose();
+        }
     }
 
     internal class ScenarioDataPerGraph
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/StepDefinition.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/StepDefinition.cs
index 3412fbd..a7a48f9 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/StepDefinition.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/StepDefinition.cs
@@ -21,19 +21,12 @@
 
 #endregion
 
-using System;
-using System.Dynamic;
-using Gremlin.Net.IntegrationTest.Process.Traversal.DriverRemoteConnection;
-
 namespace Gremlin.Net.IntegrationTest.Gherkin
 {
-    public abstract class StepDefinition : IDisposable
+    /// <summary>
+    /// This is the base class for all steps which we use for reflection to identify step types.
+    /// </summary>
+    public abstract class StepDefinition
     {
-        internal RemoteConnectionFactory ConnectionFactory = new RemoteConnectionFactory();
-
-        public virtual void Dispose()
-        {
-            ConnectionFactory.Dispose();
-        }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/ContextBasedParameter.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/ContextBasedParameter.cs
deleted file mode 100644
index fa8f3f1..0000000
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/ContextBasedParameter.cs
+++ /dev/null
@@ -1,83 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-using System;
-using System.Collections.Generic;
-
-namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation
-{
-    public class ContextBasedParameter : ITokenParameter, IEquatable<ContextBasedParameter>
-    {
-        public bool Equals(ContextBasedParameter other)
-        {
-            return string.Equals(_name, other._name) && Equals(_value, other._value);
-        }
-
-        public override bool Equals(object obj)
-        {
-            if (ReferenceEquals(null, obj)) return false;
-            if (ReferenceEquals(this, obj)) return true;
-            if (obj.GetType() != GetType()) return false;
-            return Equals((ContextBasedParameter) obj);
-        }
-
-        public override int GetHashCode()
-        {
-            unchecked
-            {
-                return ((_name != null ? _name.GetHashCode() : 0) * 397) ^ (_value != null ? _value.GetHashCode() : 0);
-            }
-        }
-
-        private readonly string _name;
-        private object _value;
-
-        public ContextBasedParameter(string name)
-        {
-            _name = name;
-        }
-
-        public void SetContextParameterValues(IDictionary<string, object> parameterValues)
-        {
-            if (parameterValues == null || !parameterValues.TryGetValue(_name, out var value))
-            {
-                throw new InvalidOperationException($"Parameter \"{_name}\" was not provided");
-            }
-            _value = value;
-        }
-        
-        public object GetValue()
-        {
-            return _value;
-        }
-
-        public Type GetParameterType()
-        {
-            if (_value == null)
-            {
-                throw new NullReferenceException($"Value for parameter \"{_name}\" was not set");
-            }
-            return _value.GetType();
-        }
-    }
-}
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/IOParameter.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/IOParameter.cs
deleted file mode 100644
index 513e589..0000000
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/IOParameter.cs
+++ /dev/null
@@ -1,82 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.Dynamic;
-using System.Linq;
-using System.Reflection;
-using Gremlin.Net.Process.Traversal;
-
-namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation
-{
-    /// <summary>
-    /// Represents a parameter for the io() step - (e.g. IO.graphml)
-    /// </summary>
-    internal class IOParameter : ITokenParameter, IEquatable<IOParameter>
-    {
-        private readonly string _text;
-        private readonly string _value;
-        
-        public IOParameter(string text)
-        {
-            _text = text;
-            var separatorIndex = text.IndexOf('.');
-            _value = text.Substring(separatorIndex + 1);
-        }
-
-        public bool Equals(IOParameter other)
-        {
-            return _text == other._text;
-        }
-
-        public override bool Equals(object obj)
-        {
-            if (ReferenceEquals(null, obj)) return false;
-            if (ReferenceEquals(this, obj)) return true;
-            if (obj.GetType() != GetType()) return false;
-            return Equals((IOParameter) obj);
-        }
-
-        public override int GetHashCode()
-        {
-            return _text.GetHashCode();
-        }
-
-        public object GetValue()
-        {
-            var field = typeof(IO).GetField(_value, BindingFlags.Static | BindingFlags.Public);
-            return field.GetValue(null);
-        }
-
-        public void SetContextParameterValues(IDictionary<string, object> parameterValues)
-        {
-
-        }
-
-        public Type GetParameterType()
-        {
-            return typeof(String);
-        }
-    }
-}
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/ITokenParameter.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/ITokenParameter.cs
deleted file mode 100644
index 357e35b..0000000
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/ITokenParameter.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-using System;
-using System.Collections.Generic;
-
-namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation
-{
-    public interface ITokenParameter
-    {
-        /// <summary>
-        /// Gets the value of the parameter 
-        /// </summary>
-        object GetValue();
-
-        /// <summary>
-        /// Gets the type of the parameter
-        /// </summary>
-        Type GetParameterType();
-
-        /// <summary>
-        /// Sets the context parameter values by a given name, ie: "v1Id" = 1
-        /// </summary>
-        void SetContextParameterValues(IDictionary<string, object> values);
-    }
-}
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/LiteralParameter.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/LiteralParameter.cs
deleted file mode 100644
index da0ac24..0000000
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/LiteralParameter.cs
+++ /dev/null
@@ -1,87 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-using System;
-using System.Collections.Generic;
-
-namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation
-{
-    /// <summary>
-    /// Represents a literal (number / boolean) that is allowed as a gremlin parameter.
-    /// </summary>
-    public class LiteralParameter<T> : ITokenParameter, IEquatable<LiteralParameter<T>> where T : struct
-    {
-        public bool Equals(LiteralParameter<T> other)
-        {
-            return Value.Equals(other.Value);
-        }
-
-        public override bool Equals(object obj)
-        {
-            if (ReferenceEquals(null, obj)) return false;
-            if (ReferenceEquals(this, obj)) return true;
-            if (obj.GetType() != GetType()) return false;
-            return Equals((LiteralParameter<T>) obj);
-        }
-
-        public override int GetHashCode()
-        {
-            return Value.GetHashCode();
-        }
-
-        public T Value { get; }
-        
-        public LiteralParameter(T value)
-        {
-            Value = value;
-        }
-
-        public override string ToString()
-        {
-            return $"NumericParameter<{typeof(T).Name}>({Value})";
-        }
-
-        public object GetValue()
-        {
-            return Value;
-        }
-
-        public Type GetParameterType()
-        {
-            return typeof(T);
-        }
-
-        public void SetContextParameterValues(IDictionary<string, object> parameterValues)
-        {
-
-        }
-    }
-
-    internal static class LiteralParameter
-    {
-        public static LiteralParameter<TType> Create<TType>(TType value) where TType : struct
-        {
-            return new LiteralParameter<TType>(value);
-        }
-    }
-}
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/ModernGraphTypeInformation.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/ModernGraphTypeInformation.cs
deleted file mode 100644
index d77ec5e..0000000
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/ModernGraphTypeInformation.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Linq;
-using System.Reflection;
-using Gremlin.Net.Process.Traversal;
-
-namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation
-{
-    internal class ModernGraphTypeInformation
-    {
-        private static readonly IDictionary<string, Type> PropertyInfos = new Dictionary<string, Type>
-        {
-            {"age", typeof(int)},
-            {"name", typeof(string)},
-            {"lang", typeof(string)},
-            {"weight", typeof(float)},
-            {"gremlin.pageRankVertexProgram.pageRank", typeof(double)},
-            {"gremlin.peerPressureVertexProgram.cluster", typeof(int)},
-            {"friendRank", typeof(double)},
-            {"pageRank", typeof(double)},
-            {"foo", typeof(object)}, // used when for invalid property key lookups
-            {"friendWeight", typeof(float)},  // used in an AddVertex.feature test
-            {"performances", typeof(int)} // grateful dead graph
-        };
-        
-        /// <summary>
-        /// Gets the type argument information based on the modern graph information.
-        /// </summary>s
-        public static Type GetTypeArguments(MethodInfo method, object[] parameterValues, int genericTypeIndex)
-        {
-            var isGeneric = method.DeclaringType.GetTypeInfo().IsGenericType;
-            if (!isGeneric)
-            {
-                // Maintain object for anonymous traversal
-                return typeof(object);
-            }
-            switch (method.Name)
-            {
-                case nameof(GraphTraversal<object,object>.Properties):
-                    return typeof(object);
-                case nameof(GraphTraversal<object,object>.Values) when parameterValues.Length == 1:
-                    // The parameter contains the element property names
-                    var properties = ((IEnumerable) parameterValues[parameterValues.Length - 1]).Cast<string>();
-                    var types = properties.Select(GetElementPropertyType).ToArray();
-                    if (types.Distinct().Count() == 1)
-                    {
-                        return types[0];
-                    }
-                    return typeof(object);
-                case nameof(GraphTraversal<object,object>.Group) when genericTypeIndex == 0:
-                    // Use IDictionary<string, object> for Group
-                    return typeof(string);
-                case nameof(GraphTraversal<object,object>.Sum):
-                    return typeof(long);
-                case nameof(GraphTraversal<object,object>.Limit):
-                case nameof(GraphTraversal<object,object>.Optional):
-                case nameof(GraphTraversal<object,object>.Coalesce):
-                case nameof(GraphTraversal<object,object>.Match):
-                    // Maintain the same type
-                    return method.DeclaringType.GetGenericArguments()[1];
-                default:
-                    // default to object for this methods
-                    return typeof(object);
-            }
-        }
-
-        private static Type GetElementPropertyType(string name)
-        {
-            PropertyInfos.TryGetValue(name, out var type);
-            return type;
-        }
-    }
-}
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/PParameter.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/PParameter.cs
deleted file mode 100644
index b25faef..0000000
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/PParameter.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.Dynamic;
-using System.Linq;
-using System.Reflection;
-using Gremlin.Net.Process.Traversal;
-
-namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation
-{
-    /// <summary>
-    /// Represents a parameter for a traversal predicate (ie: P.gt())
-    /// </summary>
-    internal class PParameter : ITokenParameter, IEquatable<PParameter>
-    {
-        private IDictionary<string, object> _contextParameterValues;
-        public IList<Token> Tokens { get; }
-        
-        public PParameter(IList<Token> tokens)
-        {
-            Tokens = tokens;
-        }
-
-        public bool Equals(PParameter other)
-        {
-            return Tokens.SequenceEqual(other.Tokens);
-        }
-
-        public override bool Equals(object obj)
-        {
-            if (ReferenceEquals(null, obj)) return false;
-            if (ReferenceEquals(this, obj)) return true;
-            if (obj.GetType() != GetType()) return false;
-            return Equals((PParameter) obj);
-        }
-
-        public override int GetHashCode()
-        {
-            return Tokens != null ? Tokens.GetHashCode() : 0;
-        }
-
-        public object GetValue()
-        {
-            var type = typeof(P);
-            object instance = null;
-            for (var i = 1; i < Tokens.Count; i++)
-            {
-                var token = Tokens[i];
-                token.SetContextParameterValues(_contextParameterValues);
-                var method = type.GetMethod(TraversalParser.GetCsharpName(token.Name),
-                    BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public);
-                if (method == null)
-                {
-                    throw new InvalidOperationException($"Predicate (P) method '{token}' not found for testing");
-                }
-                
-                var parameters = method.IsStatic
-                    ? new object[] {token.Parameters.Select(p => p.GetValue()).ToArray()}
-                    : token.Parameters.Select(p => p.GetValue()).ToArray();
-                instance = method.Invoke(instance, parameters);
-            }
-            return instance;
-        }
-
-        public Type GetParameterType()
-        {
-            return typeof(P);
-        }
-
-        public void SetContextParameterValues(IDictionary<string, object> parameterValues)
-        {
-            _contextParameterValues = parameterValues;
-        }
-    }
-}
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/StaticTraversalParameter.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/StaticTraversalParameter.cs
deleted file mode 100644
index d8fad5b..0000000
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/StaticTraversalParameter.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using Gremlin.Net.Process.Traversal;
-
-namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation
-{
-    internal class StaticTraversalParameter : ITokenParameter, IEquatable<StaticTraversalParameter>
-    {
-        private readonly string _traversalText;
-        private IDictionary<string, object> _contextParameterValues;
-
-        public IList<Token> Tokens { get; }
-        
-        public StaticTraversalParameter(IList<Token> tokens, string traversalText)
-        {
-            _traversalText = traversalText;
-            Tokens = tokens;
-        }
-
-        public bool Equals(StaticTraversalParameter other)
-        {
-            return Tokens.SequenceEqual(other.Tokens);
-        }
-
-        public override bool Equals(object obj)
-        {
-            if (ReferenceEquals(null, obj)) return false;
-            if (ReferenceEquals(this, obj)) return true;
-            if (obj.GetType() != GetType()) return false;
-            return Equals((StaticTraversalParameter) obj);
-        }
-
-        public override int GetHashCode()
-        {
-            return Tokens != null ? Tokens.GetHashCode() : 0;
-        }
-
-        public object GetValue()
-        {
-            return TraversalParser.GetTraversalFromTokens(Tokens, null, _contextParameterValues, _traversalText);
-        }
-
-        public Type GetParameterType()
-        {
-            return typeof(ITraversal);
-        }
-
-        public void SetContextParameterValues(IDictionary<string, object> parameterValues)
-        {
-            _contextParameterValues = parameterValues;
-        }
-    }
-}
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/StringParameter.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/StringParameter.cs
deleted file mode 100644
index 7cb9c95..0000000
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/StringParameter.cs
+++ /dev/null
@@ -1,85 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-using System;
-using System.Collections.Generic;
-
-namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation
-{
-    internal class StringParameter : ITokenParameter, IEquatable<StringParameter>
-    {
-        public bool Equals(StringParameter other)
-        {
-            return string.Equals(Value, other.Value);
-        }
-
-        public override bool Equals(object obj)
-        {
-            if (ReferenceEquals(null, obj)) return false;
-            if (ReferenceEquals(this, obj)) return true;
-            if (obj.GetType() != GetType()) return false;
-            return Equals((StringParameter) obj);
-        }
-
-        public override int GetHashCode()
-        {
-            return (Value != null ? Value.GetHashCode() : 0);
-        }
-
-        public string Value { get; }
-
-        public StringParameter(string value)
-        {
-            Value = value;
-        }
-
-        public static StringParameter Parse(string text, char quoteChar, ref int i)
-        {
-            i++;
-            var endIndex = text.IndexOf(quoteChar, i);
-            var result = new StringParameter(text.Substring(i, endIndex - i));
-            i = endIndex;
-            return result;
-        }
-
-        public override string ToString()
-        {
-            return $"{GetType().Name}({Value})";
-        }
-
-        public object GetValue()
-        {
-            return Value;
-        }
-
-        public Type GetParameterType()
-        {
-            return typeof(string);
-        }
-
-        public void SetContextParameterValues(IDictionary<string, object> parameterValues)
-        {
-
-        }
-    }
-}
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TextPParameter.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TextPParameter.cs
deleted file mode 100644
index 198cd74..0000000
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TextPParameter.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.Dynamic;
-using System.Linq;
-using System.Reflection;
-using Gremlin.Net.Process.Traversal;
-
-namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation
-{
-    /// <summary>
-    /// Represents a parameter for a traversal predicate (ie: TextP.containing())
-    /// </summary>
-    internal class TextPParameter : ITokenParameter, IEquatable<TextPParameter>
-    {
-        private IDictionary<string, object> _contextParameterValues;
-        public IList<Token> Tokens { get; }
-        
-        public TextPParameter(IList<Token> tokens)
-        {
-            Tokens = tokens;
-        }
-
-        public bool Equals(TextPParameter other)
-        {
-            return Tokens.SequenceEqual(other.Tokens);
-        }
-
-        public override bool Equals(object obj)
-        {
-            if (ReferenceEquals(null, obj)) return false;
-            if (ReferenceEquals(this, obj)) return true;
-            if (obj.GetType() != GetType()) return false;
-            return Equals((TextPParameter) obj);
-        }
-
-        public override int GetHashCode()
-        {
-            return Tokens != null ? Tokens.GetHashCode() : 0;
-        }
-
-        public object GetValue()
-        {
-            var type = typeof(TextP);
-            object instance = null;
-            for (var i = 1; i < Tokens.Count; i++)
-            {
-                var token = Tokens[i];
-                token.SetContextParameterValues(_contextParameterValues);
-                var method = type.GetMethod(TraversalParser.GetCsharpName(token.Name),
-                    BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public);
-                if (method == null)
-                {
-                    throw new InvalidOperationException($"Predicate (TextP) method '{token}' not found for testing");
-                }
-                
-                var parameters = method.IsStatic
-                    ? new object[] {token.Parameters.Select(p => p.GetValue().ToString()).First()}
-                    : token.Parameters.Select(p => p.GetValue()).ToArray();
-                instance = method.Invoke(instance, parameters);
-            }
-            return instance;
-        }
-
-        public Type GetParameterType()
-        {
-            return typeof(TextP);
-        }
-
-        public void SetContextParameterValues(IDictionary<string, object> parameterValues)
-        {
-            _contextParameterValues = parameterValues;
-        }
-    }
-}
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/Token.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/Token.cs
deleted file mode 100644
index 67c2af1..0000000
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/Token.cs
+++ /dev/null
@@ -1,92 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Linq;
-
-namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation
-{
-    internal class Token : IEquatable<Token>
-    {
-        private static readonly IList<ITokenParameter> EmptyParameters =
-            new ReadOnlyCollection<ITokenParameter>(new ITokenParameter[0]);
-        
-        public bool Equals(Token other)
-        {
-            if (!string.Equals(Name, other.Name))
-            {
-                return false;
-            }
-            return  (Parameters).SequenceEqual(other.Parameters);
-        }
-
-        public override bool Equals(object obj)
-        {
-            if (ReferenceEquals(null, obj)) return false;
-            if (ReferenceEquals(this, obj)) return true;
-            if (obj.GetType() != GetType()) return false;
-            return Equals((Token) obj);
-        }
-
-        public override int GetHashCode()
-        {
-            unchecked
-            {
-                return ((Name != null ? Name.GetHashCode() : 0) * 397) ^
-                       (Parameters != null ? Parameters.GetHashCode() : 0);
-            }
-        }
-
-        public string Name { get; }
-
-        /// <summary>
-        /// Returns the collection of parameters, can not be null.
-        /// </summary>
-        public IList<ITokenParameter> Parameters { get; }
-            
-        public Token(string name, IList<ITokenParameter> parameters = null)
-        {
-            Name = name.Trim();
-            Parameters = parameters ?? EmptyParameters;
-        }
-            
-        public Token(string name, ITokenParameter parameter)
-        {
-            Name = name;
-            Parameters = new[] {parameter};
-        }
-
-        /// <summary>
-        /// Sets the context parameter values by a given name, ie: "v1Id" = 1
-        /// </summary>
-        public void SetContextParameterValues(IDictionary<string, object> values)
-        {
-            foreach (var tokenParameter in Parameters)
-            {
-                tokenParameter.SetContextParameterValues(values);
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalEnumParameter.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalEnumParameter.cs
deleted file mode 100644
index 9457cae..0000000
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalEnumParameter.cs
+++ /dev/null
@@ -1,102 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Reflection;
-using Gremlin.Net.Process.Traversal;
-
-namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation
-{
-    /// <summary>
-    /// Represents a parameter for a traversal token (ie: T.label)
-    /// </summary>
-    internal class TraversalEnumParameter : ITokenParameter, IEquatable<TraversalEnumParameter>
-    {
-        private readonly string _text;
-
-        private static readonly IDictionary<string, Type> EnumTypesByName = typeof(Scope).GetTypeInfo().Assembly
-            .GetTypes().Where(t => t.GetTypeInfo().IsSubclassOf(typeof(EnumWrapper)) && t.GetTypeInfo().IsPublic)
-            .ToDictionary(e => e.Name, e => e);
-        
-        private readonly object _value;
-        private readonly Type _type;
-        
-        public TraversalEnumParameter(string text)
-        {
-            _text = text;
-            var separatorIndex = text.IndexOf('.');
-            var enumTypeName = text.Substring(0, separatorIndex);
-            if (!EnumTypesByName.TryGetValue(enumTypeName, out var type))
-            {
-                throw new KeyNotFoundException($"Enum with name {enumTypeName} not found");
-            }
-            _type = type;
-            var valueName = text.Substring(separatorIndex + 1);
-            _value = _type.GetProperty(GetCsharpName(valueName)).GetValue(null);
-        }
-
-        private string GetCsharpName(string valueText)
-        {
-            if (_type == typeof(Direction))
-            {
-                valueText = valueText.ToLower();
-            }
-            return TraversalParser.GetCsharpName(valueText);
-        }
-
-        public bool Equals(TraversalEnumParameter other)
-        {
-            return _text == other._text;
-        }
-
-        public override bool Equals(object obj)
-        {
-            if (ReferenceEquals(null, obj)) return false;
-            if (ReferenceEquals(this, obj)) return true;
-            if (obj.GetType() != GetType()) return false;
-            return Equals((TraversalEnumParameter) obj);
-        }
-
-        public override int GetHashCode()
-        {
-            return _text.GetHashCode();
-        }
-
-        public object GetValue()
-        {
-            return _value;
-        }
-
-        public Type GetParameterType()
-        {
-            return _type;
-        }
-
-        public void SetContextParameterValues(IDictionary<string, object> parameterValues)
-        {
-
-        }
-    }
-}
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalEvaluationTests.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalEvaluationTests.cs
deleted file mode 100644
index 8e725e5..0000000
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalEvaluationTests.cs
+++ /dev/null
@@ -1,115 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-using System;
-using System.Linq;
-using Xunit;
-
-using static Gremlin.Net.Process.Traversal.AnonymousTraversalSource;
-
-namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation
-{
-    public class TraversalEvaluationTests
-    {
-        [Fact]
-        public void Traversal_Parser_Should_Parse_Into_Tokens()
-        {
-            var items = new[]
-            {
-                Tuple.Create("g.V().count()", new[] {new Token("count")}),
-                Tuple.Create("g.V().values(\"name\")",
-                    new[] {new Token("values", new StringParameter("name"))}),
-                Tuple.Create("g.V().constant(123l)", 
-                    new[] {new Token("constant", new[] {LiteralParameter.Create(123L)})}),
-                Tuple.Create("g.V().constant(123)", 
-                    new[] {new Token("constant", new[] {LiteralParameter.Create(123)})}),
-                Tuple.Create("g.V().constant(123.50)", 
-                    new[] {new Token("constant", new[] {LiteralParameter.Create(123.50m)})}),
-                Tuple.Create("g.V().constant(123.1f)", 
-                    new[] {new Token("constant", new[] {LiteralParameter.Create(123.1f)})}),
-                Tuple.Create("g.V().has(\"no\").count()",
-                    new[] {new Token("has", new StringParameter("no")), new Token("count")}),
-                Tuple.Create("g.V().has(\"lang\", \"java\")",
-                    new[] {new Token("has", new[] {new StringParameter("lang"), new StringParameter("java")})}),
-                Tuple.Create("g.V().where(__.in(\"knows\"))",
-                    new[] {new Token("where", new[] {new StaticTraversalParameter(
-                        new[] {new Token("__"), new Token("in", new StringParameter("knows"))}, "__.in(\"knows\")")})}),
-                Tuple.Create("g.V().has(\"age\",P.gt(27))", 
-                    new[] {new Token("has", new ITokenParameter[] { new StringParameter("age"),
-                        new PParameter(
-                            new[] { new Token("P"), new Token("gt", LiteralParameter.Create(27)) }) })}),
-                Tuple.Create("g.V().count(Scope.local)", 
-                    new[] { new Token("count", new TraversalEnumParameter("Scope.local"))}),
-                Tuple.Create("g.V().\n  count()", new[] { new Token("count")}),
-                Tuple.Create("g.V().\n has ( \"a\" ) \n.  \ncount()",
-                    new[] {new Token("has", new StringParameter("a")), new Token("count")}),
-                Tuple.Create("g.V().choose(__.outE(),__.as(\"a\"))", new []
-                {
-                    new Token("choose", new ITokenParameter[] { 
-                        new StaticTraversalParameter(new[] {new Token("__"), new Token("outE")}, "__.outE()"),
-                        new StaticTraversalParameter(
-                            new[] {new Token("__"), new Token("as", new StringParameter("a"))}, "__.as(\"a\")")
-                    })
-                })
-            };
-            foreach (var item in items)
-            {
-                var parts = TraversalParser.ParseTraversal(item.Item1);
-                Assert.Equal(item.Item2, parts.Skip(2));
-            }
-        }
-
-        [Fact]
-        public void GetTraversal_Should_Invoke_Traversal_Methods()
-        {
-            var traversalTexts = new []
-            {
-                Tuple.Create("g.V().count()", 2),
-//                Tuple.Create("g.V().constant(123L)", 2), // Can be parsed using the new type-safe API
-                Tuple.Create("g.V().has(\"no\").count()", 3),
-                Tuple.Create("g.V().values(\"age\")", 2),
-                Tuple.Create("g.V().valueMap(\"name\", \"age\").with(WithOptions.tokens)", 3),
-                Tuple.Create("g.V().where(__.in(\"created\").count().is(1)).values(\"name\")", 3),
-                Tuple.Create("g.V().count(Scope.local)", 2),
-                Tuple.Create("g.V().values(\"age\").is(P.lte(30))", 3),
-                Tuple.Create("g.V().optional(__.out().optional(__.out())).path().limit(1)", 4),
-                Tuple.Create("g.V(1).as(\"a\").out(\"knows\").as(\"b\").\n  select(\"a\", \"b\").by(\"name\")", 6),
-                Tuple.Create(
-                    "g.V().hasLabel(\"software\").group().by(\"name\").by(__.bothE().values(\"weight\").sum())", 5),
-                Tuple.Create("g.V().choose(__.outE().count().is(0L),__.as(\"a\"),__.as(\"b\"))" +
-                                  "\n.choose(__.select(\"a\"),__.select(\"a\"),__.select(\"b\"))", 3),
-                Tuple.Create("g.V().repeat(__.out()).times(2) ", 3),
-                Tuple.Create("g.V().local(__.match(\n   __.as(\"project\").in(\"created\").as(\"person\"),\n__.as(\"person\").values(\"name\").as(\"name\"))).select(\"name\", \"project\").by().by(\"name\")", 5),
-                Tuple.Create("g.V().as(\"a\").out().as(\"a\").out().as(\"a\").select(\"a\").by(__.unfold().values(\"name\").fold()).tail(Scope.local, 2)", 9),
-                Tuple.Create("g.V().coin(1.0)", 2)
-            };
-            var g = Traversal();
-            foreach (var tuple in traversalTexts)
-            {
-                var traversal = TraversalParser.GetTraversal(tuple.Item1, g, null);
-                Assert.NotNull(traversal);
-                Assert.Equal(tuple.Item2, traversal.Bytecode.StepInstructions.Count);
-            }
-        }
-    }
-}
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalParser.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalParser.cs
deleted file mode 100644
index 105932f..0000000
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalParser.cs
+++ /dev/null
@@ -1,509 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using System.Reflection;
-using System.Text.RegularExpressions;
-using Gremlin.Net.Process.Traversal;
-
-namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation
-{
-    public class TraversalParser
-    {
-        private static readonly IDictionary<string, Func<GraphTraversalSource, ITraversal>> FixedTranslations = 
-            new Dictionary<string, Func<GraphTraversalSource, ITraversal>>
-            {
-                { "g.V().fold().count(Scope.local)", g => g.V().Fold().Count(Scope.Local)}
-            };
-
-        private static readonly Regex RegexNumeric =
-            new Regex(@"\d+(\.\d+)?(?:l|f)?", RegexOptions.Compiled | RegexOptions.IgnoreCase);
-
-        private static readonly Regex RegexEnum = new Regex(@"\w+\.\w+", RegexOptions.Compiled);
-
-        private static readonly Regex RegexIO = new Regex(@"IO.\w+", RegexOptions.Compiled);
-
-        private static readonly Regex RegexWithOptions = new Regex(@"WithOptions.\w+", RegexOptions.Compiled);
-
-        private static readonly Regex RegexParam = new Regex(@"\w+", RegexOptions.Compiled);
-        
-        private static readonly HashSet<Type> NumericTypes = new HashSet<Type>
-        {
-            typeof(int), typeof(long), typeof(double), typeof(float), typeof(short), typeof(decimal), typeof(byte)
-        };
-
-        internal static ITraversal GetTraversal(string traversalText, GraphTraversalSource g,
-                                                IDictionary<string, object> contextParameterValues)
-        {
-            if (!FixedTranslations.TryGetValue(traversalText, out var traversalBuilder))
-            {
-                var tokens = ParseTraversal(traversalText);
-                return GetTraversalFromTokens(tokens, g, contextParameterValues, traversalText);
-            }
-            return traversalBuilder(g);
-        }
-
-        internal static ITraversal GetTraversalFromTokens(IList<Token> tokens, GraphTraversalSource g,
-                                                          IDictionary<string, object> contextParameterValues,
-                                                          string traversalText)
-        {
-            object instance;
-            Type instanceType;
-            if (tokens[0].Name == "g")
-            {
-                instance = g;
-                instanceType = g.GetType();
-            }
-            else if (tokens[0].Name == "__")
-            {
-                instance = null;
-                instanceType = typeof(__);
-            }
-            else
-            {
-                throw BuildException(traversalText);
-            }
-            for (var i = 1; i < tokens.Count; i++)
-            {
-                var token = tokens[i];
-                token.SetContextParameterValues(contextParameterValues);
-                var name = GetCsharpName(token.Name);
-                var methods = instanceType.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)
-                    .Where(m => m.Name == name).ToList();
-                var method = GetClosestMethod(methods, token.Parameters);
-                if (method == null)
-                {
-                    throw new InvalidOperationException($"Traversal method '{tokens[i].Name}' not found for testing");
-                }
-                var parameterValues = BuildParameters(method, token, out var genericParameters);
-                method = BuildGenericMethod(method, genericParameters, parameterValues);
-                instance = method.Invoke(instance, parameterValues);
-                instanceType = instance.GetType();
-            }
-            return (ITraversal) instance;
-        }
-
-        /// <summary>
-        /// Find the method that supports the amount of parameters provided
-        /// </summary>
-        private static MethodInfo GetClosestMethod(IList<MethodInfo> methods, IList<ITokenParameter> tokenParameters)
-        {
-            if (methods.Count == 0)
-            {
-                return null;
-            }
-            if (methods.Count == 1)
-            {
-                return methods[0];
-            }
-            var ordered = methods.OrderBy(m => m.GetParameters().Length);
-            if (tokenParameters.Count == 0)
-            {
-                return ordered.First();
-            }
-            MethodInfo lastMethod = null;
-            var compatibleMethods = new Dictionary<int, MethodInfo>();
-            foreach (var method in ordered)
-            {
-                var methodParameters = method.GetParameters();
-                var requiredParameters = methodParameters.Length;
-                if (requiredParameters > 0 && IsParamsArray(methodParameters.Last()))
-                {
-                    // Params array can be not provided
-                    requiredParameters--;
-                }
-                if (tokenParameters.Count < requiredParameters)
-                {
-                    continue;
-                }
-                lastMethod = method;
-                var matched = true;
-                var exactMatches = 0;
-                for (var i = 0; i < tokenParameters.Count; i++)
-                {
-                    if (methodParameters.Length <= i)
-                    {
-                        // The method contains less parameters (and no params array) than provided
-                        matched = false;
-                        break;
-                    }
-                    var methodParameter = methodParameters[i];
-                    var tokenParameterType = tokenParameters[i].GetParameterType();
-                    // Match either the same parameter type
-                    matched = methodParameter.ParameterType == tokenParameterType;
-                    if (matched)
-                    {
-                        exactMatches++;
-                    }
-                    else if (IsParamsArray(methodParameter))
-                    {
-                        matched = methodParameter.ParameterType == typeof(object[]) ||
-                                  methodParameter.ParameterType.GetElementType() == tokenParameterType;
-                        // The method has params array, no further parameters are going to be defined
-                        break;
-                    }
-                    else
-                    {
-                        if (IsNumeric(methodParameter.ParameterType) && IsNumeric(tokenParameterType))
-                        {
-                            // Acount for implicit conversion of numeric values as an exact match 
-                            exactMatches++;
-                        }
-                        else if (!methodParameter.ParameterType.GetTypeInfo().IsAssignableFrom(tokenParameterType))
-                        {
-                            // Not a match
-                            break;
-                        }
-                        // Is assignable to the parameter type
-                        matched = true;
-                    }
-                }
-                if (matched)
-                {
-                    compatibleMethods[exactMatches] = method;
-                }
-            }
-            // Attempt to use the method with the higher number of matches or the last one
-            return compatibleMethods.OrderByDescending(kv => kv.Key).Select(kv => kv.Value).FirstOrDefault() ??
-                   lastMethod;
-        }
-
-        private static bool IsNumeric(Type t) => NumericTypes.Contains(t);
-
-        private static bool IsParamsArray(ParameterInfo methodParameter)
-        {
-            return methodParameter.IsDefined(typeof(ParamArrayAttribute), false);
-        }
-
-        private static MethodInfo BuildGenericMethod(MethodInfo method, IDictionary<string, Type> genericParameters,
-                                                     object[] parameterValues)
-        {
-            if (!method.IsGenericMethod)
-            {
-                return method;
-            }
-            var genericArgs = method.GetGenericArguments();
-            var types = new Type[genericArgs.Length];
-            for (var i = 0; i < genericArgs.Length; i++)
-            {
-                var name = genericArgs[i].Name;
-                Type type;
-                if (!genericParameters.TryGetValue(name, out type))
-                {
-                    // Try to infer it from the name based on modern graph
-                    type = ModernGraphTypeInformation.GetTypeArguments(method, parameterValues, i);
-                }
-                if (type == null)
-                {
-                    throw new InvalidOperationException(
-                        $"Can not build traversal to test as '{method.Name}()' method is generic and type '{name}'" +
-                         " can not be inferred");
-                }
-                types[i] = type;
-            }
-            return method.MakeGenericMethod(types);
-        }
-
-        private static object[] BuildParameters(MethodInfo method, Token token,
-                                                out IDictionary<string, Type> genericParameterTypes)
-        {
-            var paramsInfo = method.GetParameters();
-            var parameters = new object[paramsInfo.Length];
-            genericParameterTypes = new Dictionary<string, Type>();
-            for (var i = 0; i < paramsInfo.Length; i++)
-            {
-                var info = paramsInfo[i];
-                object value = null;
-                if (token.Parameters.Count > i)
-                {
-                    var tokenParameter = token.Parameters[i];
-                    value =  tokenParameter.GetValue();
-                    if (info.ParameterType.IsGenericParameter)
-                    {
-                        // We've provided a value for parameter of a generic type, we can infer the
-                        // type of the generic argument based on the parameter.
-                        // For example, in the case of `Constant<E2>(E2 value)`
-                        // if we have the type of value we have the type of E2. 
-                        genericParameterTypes.Add(info.ParameterType.Name, tokenParameter.GetParameterType());
-                    }
-                    else if (IsParamsArray(info) && info.ParameterType.GetElementType().IsGenericParameter)
-                    {
-                        // Its a method where the type parameter comes from an params Array
-                        // e.g., Inject<S>(params S[] value)
-                        genericParameterTypes.Add(info.ParameterType.GetElementType().Name,
-                            tokenParameter.GetParameterType());
-                    }
-
-                    if (info.ParameterType != tokenParameter.GetParameterType() && IsNumeric(info.ParameterType) &&
-                        IsNumeric(tokenParameter.GetParameterType()))
-                    {
-                        // Numeric conversion
-                        value = Convert.ChangeType(value, info.ParameterType);
-                    }
-                }
-
-                if (IsParamsArray(info))
-                {
-                    // For `params type[] value` we should provide an empty array
-                    if (value == null)
-                    {
-                        // An empty array
-                        value = Array.CreateInstance(info.ParameterType.GetElementType(), 0);
-                    }
-                    else if (!value.GetType().IsArray)
-                    {
-                        // An array with the parameter values
-                        // No more method parameters after this one
-                        var elementType = info.ParameterType.GetElementType();
-
-                        if (elementType.IsGenericParameter)
-                        {
-                            // The Array element type is generic, so we use type of the value to specify it
-                            elementType = value.GetType();
-                        }
-
-                        var arr = Array.CreateInstance(elementType, token.Parameters.Count - i);
-                        arr.SetValue(value, 0);
-                        for (var j = 1; j < token.Parameters.Count - i; j++)
-                        {
-                            arr.SetValue(token.Parameters[i + j].GetValue(), j);
-                        }
-                        value = arr;
-                    }
-                }
-                parameters[i] = value ?? GetDefault(info.ParameterType);
-            }
-            return parameters;
-        }
-
-        public static object GetDefault(Type type)
-        {
-            return type.GetTypeInfo().IsValueType ? Activator.CreateInstance(type) : null;
-        }
-
-        internal static string GetCsharpName(string part)
-        {
-            // Transform to PascalCasing and remove the parenthesis
-            return char.ToUpper(part[0]) + part.Substring(1);
-        }
-
-        private static Exception BuildException(string traversalText)
-        {
-            return new InvalidOperationException($"Can not build a traversal to test from '{traversalText}'");
-        }
-
-        internal static IList<Token> ParseTraversal(string traversalText)
-        {
-            var index = 0;
-            return ParseTokens(traversalText, ref index);
-        }
-
-        private static IList<Token> ParseTokens(string text, ref int i)
-        {
-            // Parser issue: quotes are not normalized
-            text = text.Replace("\\\"", "\"");
-            var result = new List<Token>();
-            var startIndex = i;
-            var parsing = ParsingPart.Name;
-            var parameters = new List<ITokenParameter>();
-            string name = null;
-            while (i < text.Length)
-            {
-                switch (text[i])
-                {
-                    case '.':
-                        if (parsing == ParsingPart.Name)
-                        {
-                            // The previous token was an object property, not a method
-                            result.Add(new Token(text.Substring(startIndex, i - startIndex)));
-                        }
-                        startIndex = i + 1;
-                        parameters = new List<ITokenParameter>();
-                        parsing = ParsingPart.Name;
-                        break;
-                    case '(':
-                    {
-                        name = text.Substring(startIndex, i - startIndex);
-                        parsing = ParsingPart.StartParameters;
-                        // Start parsing from the next index
-                        i++;
-                        var param = ParseParameter(text, ref i);
-                        if (param == null)
-                        {
-                            // The next character was a ')', empty params
-                            // Evaluate the current position
-                            continue;
-                        }
-                        parameters.Add(param);
-                        break;
-                    }
-                    case ',' when parsing == ParsingPart.StartParameters && text.Length > i + 1 && text[i+1] != ' ':
-                    case ' ' when parsing == ParsingPart.StartParameters && text.Length > i + 1 && text[i+1] != ' ' &&
-                                  text[i+1] != ')':
-                    {
-                        i++;
-                        var param = ParseParameter(text, ref i);
-                        if (param == null)
-                        {
-                            // The next character was a ')', empty params
-                            // Evaluate the current position
-                            continue;
-                        }
-                        parameters.Add(param);
-                        break;
-                    }
-                    case ',' when parsing != ParsingPart.StartParameters:
-                    case ')' when parsing != ParsingPart.StartParameters:
-                        // The current nested object already ended
-                        if (parsing == ParsingPart.Name)
-                        {
-                            // The previous token was an object property, not a method and finished
-                            result.Add(new Token(text.Substring(startIndex, i - startIndex)));
-                        }
-                        i--;
-                        return result;
-                    case ')':
-                        parsing = ParsingPart.EndParameters;
-                        result.Add(new Token(name, parameters));
-                        break;
-                }
-                i++;
-            }
-            if (parsing == ParsingPart.Name)
-            {
-                // The previous token was an object property, not a method and finished
-                result.Add(new Token(text.Substring(startIndex, i - startIndex)));
-            }
-            return result;
-        }
-
-        private static ITokenParameter ParseParameter(string text, ref int i)
-        {
-            var firstChar = text[i];
-            while (char.IsWhiteSpace(firstChar))
-            {
-                firstChar = text[++i];
-            }
-            if (firstChar == ')')
-            {
-                return null;
-            }
-            if (firstChar == '"' || firstChar == '\'')
-            {
-                return StringParameter.Parse(text, firstChar, ref i);
-            }
-            if (char.IsDigit(firstChar))
-            {
-                return ParseNumber(text, ref i);
-            }
-            if (text.Length >= i + 3 && text.Substring(i, 3) == "__.")
-            {
-                var startIndex = i;
-                var tokens = ParseTokens(text, ref i);
-                return new StaticTraversalParameter(tokens, text.Substring(startIndex, i - startIndex));
-            }
-            if (text.Length >= i + 6 && text.Substring(i, 6) == "TextP.")
-            {
-                return new TextPParameter(ParseTokens(text, ref i));
-            }
-            if (text.Substring(i, 2).StartsWith("P."))
-            {
-                return new PParameter(ParseTokens(text, ref i));
-            }
-            var parameterText = text.Substring(i, text.IndexOf(')', i) - i);
-            var separatorIndex = parameterText.IndexOf(',');
-            if (separatorIndex >= 0)
-            {
-                parameterText = parameterText.Substring(0, separatorIndex);
-            }
-            parameterText = parameterText.Trim();
-            if (parameterText == "")
-            {
-                return null;
-            }
-            if (parameterText == "true" || parameterText == "false")
-            {
-                i += parameterText.Length - 1;
-                return LiteralParameter.Create(Convert.ToBoolean(parameterText));
-            }
-            if (RegexIO.IsMatch(parameterText))
-            {
-                i += parameterText.Length - 1;
-                return new IOParameter(parameterText);
-            }
-            if (RegexWithOptions.IsMatch(parameterText))
-            {
-                i += parameterText.Length - 1;
-                return new WithOptionsParameter(parameterText);
-            }
-            if (RegexEnum.IsMatch(parameterText))
-            {
-                i += parameterText.Length - 1;
-                return new TraversalEnumParameter(parameterText);
-            }
-            if (RegexParam.IsMatch(parameterText))
-            {
-                i += parameterText.Length - 1;
-                return new ContextBasedParameter(parameterText);
-            }
-            throw new NotSupportedException($"Parameter {parameterText} not supported");
-        }
-        
-        private static ITokenParameter ParseNumber(string text, ref int i)
-        {
-            var match = RegexNumeric.Match(text, i);
-            if (!match.Success)
-            {
-                throw new InvalidOperationException(
-                    $"Could not parse numeric value from the beginning of {text.Substring(i)}");
-            }
-            var numericText = match.Value.ToUpper();
-            i += match.Value.Length - 1;
-            if (numericText.EndsWith("L"))
-            {
-                return LiteralParameter.Create(Convert.ToInt64(match.Value.Substring(0, match.Value.Length - 1)));
-            }
-            if (numericText.EndsWith("F"))
-            {
-                return LiteralParameter.Create(Convert.ToSingle(match.Value.Substring(0, match.Value.Length - 1),
-                    CultureInfo.InvariantCulture));
-            }
-            if (match.Groups[1].Value != "")
-            {
-                // Captured text with the decimal separator
-                return LiteralParameter.Create(Convert.ToDecimal(match.Value, CultureInfo.InvariantCulture));
-            }
-            return LiteralParameter.Create(Convert.ToInt32(match.Value));
-        }
-        
-        private enum ParsingPart
-        {
-            Name,
-            StartParameters,
-            EndParameters
-        }
-    }
-}
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/WithOptionsParameter.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/WithOptionsParameter.cs
deleted file mode 100644
index 9b055ec..0000000
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/WithOptionsParameter.cs
+++ /dev/null
@@ -1,83 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.Dynamic;
-using System.Linq;
-using System.Reflection;
-using Gremlin.Net.Process.Traversal.Step.Util;
-
-namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation
-{
-    /// <summary>
-    /// Represents a parameter for the with() step
-    /// </summary>
-    internal class WithOptionsParameter : ITokenParameter, IEquatable<WithOptionsParameter>
-    {
-        private readonly string _text;
-        private readonly string _value;
-        
-        public WithOptionsParameter(string text)
-        {
-            _text = text;
-            var separatorIndex = text.IndexOf('.');
-            var value = text.Substring(separatorIndex + 1);
-            _value = value.Substring(0, 1).ToUpper() + value.Substring(1);
-        }
-
-        public bool Equals(WithOptionsParameter other)
-        {
-            return _text == other._text;
-        }
-
-        public override bool Equals(object obj)
-        {
-            if (ReferenceEquals(null, obj)) return false;
-            if (ReferenceEquals(this, obj)) return true;
-            if (obj.GetType() != GetType()) return false;
-            return Equals((WithOptionsParameter) obj);
-        }
-
-        public override int GetHashCode()
-        {
-            return _text.GetHashCode();
-        }
-
-        public object GetValue()
-        {
-            var field = typeof(WithOptions).GetField(_value, BindingFlags.Static | BindingFlags.Public);
-            return field.GetValue(null);
-        }
-
-        public void SetContextParameterValues(IDictionary<string, object> parameterValues)
-        {
-
-        }
-
-        public Type GetParameterType()
-        {
-            return typeof(object);
-        }
-    }
-}
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/GraphTraversalTests.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/GraphTraversalTests.cs
index 42d1923..89597a3 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/GraphTraversalTests.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/GraphTraversalTests.cs
@@ -223,6 +223,20 @@
         }
 
         [Fact]
+        public void ShouldUseSeedStrategyToReturnDeterministicResults()
+        {
+            var connection = _connectionFactory.CreateRemoteConnection();
+            var g = AnonymousTraversalSource.Traversal().WithRemote(connection).WithStrategies(new SeedStrategy(664664));
+
+            var shuffledResults = g.V().Values<string>("name").Order().By(Order.Shuffle).ToList();
+            Assert.Equal(shuffledResults, g.V().Values<string>("name").Order().By(Order.Shuffle).ToList());
+            Assert.Equal(shuffledResults, g.V().Values<string>("name").Order().By(Order.Shuffle).ToList());
+            Assert.Equal(shuffledResults, g.V().Values<string>("name").Order().By(Order.Shuffle).ToList());
+            Assert.Equal(shuffledResults, g.V().Values<string>("name").Order().By(Order.Shuffle).ToList());
+            Assert.Equal(shuffledResults, g.V().Values<string>("name").Order().By(Order.Shuffle).ToList());
+        }
+
+        [Fact]
         public async Task ShouldExecuteAsynchronouslyWhenPromiseIsCalled()
         {
             var connection = _connectionFactory.CreateRemoteConnection();
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/RemoteConnectionFactory.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/RemoteConnectionFactory.cs
index a997167..bb7bacc 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/RemoteConnectionFactory.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/RemoteConnectionFactory.cs
@@ -25,6 +25,7 @@
 using System.Collections.Generic;
 using Gremlin.Net.Driver;
 using Gremlin.Net.Process.Remote;
+using Gremlin.Net.Structure.IO.GraphSON;
 using DriverRemoteConnectionImpl = Gremlin.Net.Driver.Remote.DriverRemoteConnection;
 
 namespace Gremlin.Net.IntegrationTest.Process.Traversal.DriverRemoteConnection
@@ -35,7 +36,13 @@
         private static readonly int TestPort = Convert.ToInt32(ConfigProvider.Configuration["TestServerPort"]);
 
         private readonly IList<DriverRemoteConnectionImpl> _connections = new List<DriverRemoteConnectionImpl>();
+        private readonly IMessageSerializer _messageSerializer;
 
+        public RemoteConnectionFactory(IMessageSerializer messageSerializer = null)
+        {
+            _messageSerializer = messageSerializer ?? new GraphSON3MessageSerializer();
+        }
+        
         public IRemoteConnection CreateRemoteConnection()
         {
             // gmodern is the standard test traversalsource that the main body of test uses
@@ -45,7 +52,7 @@
         public IRemoteConnection CreateRemoteConnection(string traversalSource)
         {
             var c = new DriverRemoteConnectionImpl(
-                new GremlinClient(new GremlinServer(TestHost, TestPort),
+                new GremlinClient(new GremlinServer(TestHost, TestPort), _messageSerializer,
                     connectionPoolSettings: new ConnectionPoolSettings {PoolSize = 2}),
                 traversalSource);
             _connections.Add(c);
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/SideEffectTests.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/SideEffectTests.cs
deleted file mode 100644
index 5d98f97..0000000
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/SideEffectTests.cs
+++ /dev/null
@@ -1,160 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using Gremlin.Net.Process.Traversal;
-using Xunit;
-
-namespace Gremlin.Net.IntegrationTest.Process.Traversal.DriverRemoteConnection
-{
-    public class SideEffectTests
-    {
-        private readonly RemoteConnectionFactory _connectionFactory = new RemoteConnectionFactory();
-
-        [Fact]
-        public void ShouldReturnCachedSideEffectWhenGetIsCalledAfterClose()
-        {
-            var connection = _connectionFactory.CreateRemoteConnection();
-            var g = AnonymousTraversalSource.Traversal().WithRemote(connection);
-            var t = g.V().Aggregate("a").Iterate();
-
-            t.SideEffects.Get("a");
-            t.SideEffects.Close();
-            var results = t.SideEffects.Get("a");
-
-            Assert.NotNull(results);
-        }
-
-        [Fact]
-        public void ShouldThrowWhenGetIsCalledAfterCloseAndNoSideEffectsAreCachec()
-        {
-            var connection = _connectionFactory.CreateRemoteConnection();
-            var g = AnonymousTraversalSource.Traversal().WithRemote(connection);
-            var t = g.V().Aggregate("a").Iterate();
-
-            t.SideEffects.Close();
-            Assert.Throws<InvalidOperationException>(() => t.SideEffects.Get("a"));
-        }
-
-        [Fact]
-        public void ShouldThrowWhenGetIsCalledAfterDisposeAndNoSideEffectsAreCachec()
-        {
-            var connection = _connectionFactory.CreateRemoteConnection();
-            var g = AnonymousTraversalSource.Traversal().WithRemote(connection);
-            var t = g.V().Aggregate("a").Iterate();
-
-            t.SideEffects.Dispose();
-            Assert.Throws<InvalidOperationException>(() => t.SideEffects.Get("a"));
-        }
-
-        [Fact]
-        public void ShouldThrowWhenGetIsCalledWithAnUnknownKey()
-        {
-            var connection = _connectionFactory.CreateRemoteConnection();
-            var g = AnonymousTraversalSource.Traversal().WithRemote(connection);
-            var t = g.V().Iterate();
-
-            Assert.Throws<KeyNotFoundException>(() => t.SideEffects.Get("m"));
-        }
-
-        [Fact]
-        public void ShouldReturnAnEmptyCollectionWhenKeysIsCalledForTraversalWithoutSideEffect()
-        {
-            var connection = _connectionFactory.CreateRemoteConnection();
-            var g = AnonymousTraversalSource.Traversal().WithRemote(connection);
-
-            var t = g.V().Iterate();
-            var keys = t.SideEffects.Keys();
-
-            Assert.Equal(0, keys.Count);
-        }
-
-        [Fact]
-        public void ShouldReturnCachedKeysWhenForCloseAfterSomeGet()
-        {
-            var connection = _connectionFactory.CreateRemoteConnection();
-            var g = AnonymousTraversalSource.Traversal().WithRemote(connection);
-            var t = g.V().Aggregate("a").Aggregate("b").Iterate();
-
-            t.SideEffects.Get("a");
-            t.SideEffects.Close();
-            var keys = t.SideEffects.Keys();
-
-            Assert.Equal(2, keys.Count);
-            Assert.Contains("a", keys);
-            Assert.Contains("b", keys);
-        }
-
-        [Fact]
-        public void ShouldReturnSideEffectKeyWhenKeysIsCalledForNamedGroupCount()
-        {
-            var connection = _connectionFactory.CreateRemoteConnection();
-            var g = AnonymousTraversalSource.Traversal().WithRemote(connection);
-            var t = g.V().Out("created").GroupCount("m").By("name").Iterate();
-
-            var keys = t.SideEffects.Keys();
-
-            var keysList = keys.ToList();
-            Assert.Equal(1, keysList.Count);
-            Assert.Contains("m", keysList);
-        }
-
-        [Fact]
-        public async Task ShouldReturnSideEffectsKeysWhenKeysIsCalledOnTraversalThatExecutedAsynchronously()
-        {
-            var connection = _connectionFactory.CreateRemoteConnection();
-            var g = AnonymousTraversalSource.Traversal().WithRemote(connection);
-
-            var t = await g.V().Aggregate("a").Promise(x => x);
-            var keys = t.SideEffects.Keys();
-
-            Assert.Equal(1, keys.Count);
-            Assert.Contains("a", keys);
-        }
-
-        [Fact]
-        public async Task ShouldReturnSideEffectValueWhenGetIsCalledOnTraversalThatExecutedAsynchronously()
-        {
-            var connection = _connectionFactory.CreateRemoteConnection();
-            var g = AnonymousTraversalSource.Traversal().WithRemote(connection);
-
-            var t = await g.V().Aggregate("a").Promise(x => x);
-            var value = t.SideEffects.Get("a");
-
-            Assert.NotNull(value);
-        }
-
-        [Fact]
-        public async Task ShouldNotThrowWhenCloseIsCalledOnTraversalThatExecutedAsynchronously()
-        {
-            var connection = _connectionFactory.CreateRemoteConnection();
-            var g = AnonymousTraversalSource.Traversal().WithRemote(connection);
-
-            var t = await g.V().Aggregate("a").Promise(x => x);
-            t.SideEffects.Close();
-        }
-    }
-}
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/GraphSONMessageSerializerTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/GraphSONMessageSerializerTests.cs
new file mode 100644
index 0000000..6b7951f
--- /dev/null
+++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/GraphSONMessageSerializerTests.cs
@@ -0,0 +1,75 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System;
+using System.Text;
+using System.Threading.Tasks;
+using Gremlin.Net.Structure.IO.GraphSON;
+using Xunit;
+
+namespace Gremlin.Net.UnitTest.Driver
+{
+    public class GraphSONMessageSerializerTests
+    {
+        [Fact]
+        public async Task DeserializingNullThrows()
+        {
+            var sut = CreateMessageSerializer();
+
+            await Assert.ThrowsAsync<ArgumentNullException>(()=> sut.DeserializeMessageAsync(null));
+        }
+
+        [Fact]
+        public async Task EmptyArrayDeserializedIntoNull()
+        {
+            var sut = CreateMessageSerializer();
+
+            var result = await sut.DeserializeMessageAsync(new byte[0]);
+            
+            Assert.Null(result);
+        }
+
+        [Fact]
+        public async Task EmptyStringDeserializedIntoNull()
+        {
+            var sut = CreateMessageSerializer();
+            var ofEmpty = Encoding.UTF8.GetBytes("");
+
+            Assert.Null(await sut.DeserializeMessageAsync(ofEmpty));
+        }
+
+        [Fact]
+        public async Task JsonNullDeserializedIntoNull()
+        {
+            var sut = CreateMessageSerializer();
+            var ofNull = Encoding.UTF8.GetBytes("null");
+
+            Assert.Null(await sut.DeserializeMessageAsync(ofNull));
+        }
+
+        private static GraphSONMessageSerializer CreateMessageSerializer()
+        {
+            return new GraphSON3MessageSerializer(new GraphSON3Reader(), new GraphSON3Writer());
+        }
+    }
+}
diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/GremlinClientTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/GremlinClientTests.cs
index 086dc90..5f1e4c5 100644
--- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/GremlinClientTests.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/GremlinClientTests.cs
@@ -1,4 +1,4 @@
-#region License
+#region License
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -23,6 +23,8 @@
 
 using System;
 using Gremlin.Net.Driver;
+using Gremlin.Net.Structure.IO;
+using Gremlin.Net.Structure.IO.GraphSON;
 using Xunit;
 
 namespace Gremlin.Net.UnitTest.Driver
@@ -39,7 +41,40 @@
             var poolSettings = new ConnectionPoolSettings {PoolSize = 2};
 
             var gremlinServer = new GremlinServer(host, port);
-            Assert.Throws<ArgumentOutOfRangeException>(() => new GremlinClient(gremlinServer, connectionPoolSettings: poolSettings, sessionId: sessionId));
+            Assert.Throws<ArgumentOutOfRangeException>(() =>
+                new GremlinClient(gremlinServer, connectionPoolSettings: poolSettings, sessionId: sessionId));
         }
+
+#pragma warning disable 612,618
+        [Fact]
+        public void ShouldThrowForInvalidGraphSONReaderWriterCombination()
+        {
+            Assert.Throws<ArgumentException>(() =>
+                new GremlinClient(new GremlinServer(), new GraphSON2Reader(), new GraphSON3Writer()));
+        }
+        
+        [Fact]
+        public void ShouldThrowForInvalidGraphSONReaderForGivenMimeType()
+        {
+            Assert.Throws<ArgumentException>(() =>
+                new GremlinClient(new GremlinServer(), new GraphSON3Reader(), new GraphSON2Writer(),
+                    SerializationTokens.GraphSON2MimeType));
+        }
+        
+        [Fact]
+        public void ShouldThrowForInvalidGraphSONWriterForGivenMimeType()
+        {
+            Assert.Throws<ArgumentException>(() =>
+                new GremlinClient(new GremlinServer(), new GraphSON2Reader(), new GraphSON3Writer(),
+                    SerializationTokens.GraphSON2MimeType));
+        }
+
+        [Fact]
+        public void ShouldThrowForUnsupportedMimeType()
+        {
+            Assert.Throws<ArgumentException>(() =>
+                new GremlinClient(new GremlinServer(), new GraphSON3Reader(), new GraphSON3Writer(), "unsupported"));
+        }
+#pragma warning restore 612,618
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/JsonMessageSerializerTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/JsonMessageSerializerTests.cs
deleted file mode 100644
index 67766a5..0000000
--- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/JsonMessageSerializerTests.cs
+++ /dev/null
@@ -1,71 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-using Gremlin.Net.Driver;
-using Gremlin.Net.Driver.Messages;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-using System;
-using System.Text;
-using Xunit;
-
-namespace Gremlin.Net.UnitTest.Driver
-{
-    // Will be used in future to switch to new .NET Core Json deserializer
-    public class JsonMessageSerializerTests
-    {
-        [Fact]
-        public void DeserializingNullThrows()
-        {
-            var sut = new JsonMessageSerializer(GremlinClient.DefaultMimeType);
-
-            Assert.Throws<ArgumentNullException>(()=> sut.DeserializeMessage<ResponseMessage<JToken>>(null));
-        }
-
-        [Fact]
-        public void EmptyArrayDeserializedIntoNull()
-        {
-            var sut = new JsonMessageSerializer(GremlinClient.DefaultMimeType);
-
-            Assert.Null(sut.DeserializeMessage<ResponseMessage<JToken>>(new byte[0]));            
-        }
-
-        [Fact]
-        public void EmptyStringDeserializedIntoNull()
-        {
-            var sut = new JsonMessageSerializer(GremlinClient.DefaultMimeType);
-            var ofEmpty = Encoding.UTF8.GetBytes("");
-
-            Assert.Null(sut.DeserializeMessage<ResponseMessage<JToken>>(ofEmpty));
-        }
-
-        [Fact]
-        public void JsonNullDeserializedIntoNull()
-        {
-            var sut = new JsonMessageSerializer(GremlinClient.DefaultMimeType);
-            var ofNull = Encoding.UTF8.GetBytes("null");
-
-            Assert.Null(sut.DeserializeMessage<ResponseMessage<JToken>>(ofNull));
-        }
-    }
-}
diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Gremlin.Net.UnitTest.csproj b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Gremlin.Net.UnitTest.csproj
index 415072f..90296be 100644
--- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Gremlin.Net.UnitTest.csproj
+++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Gremlin.Net.UnitTest.csproj
@@ -12,7 +12,6 @@
   </ItemGroup>
 
   <ItemGroup>
-    <PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
     <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
     <PackageReference Include="Moq" Version="4.7.99" />
     <PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Process/Traversal/GraphTraversalSourceTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Process/Traversal/GraphTraversalSourceTests.cs
index b3c285f..2cc39a6 100644
--- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Process/Traversal/GraphTraversalSourceTests.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Process/Traversal/GraphTraversalSourceTests.cs
@@ -21,6 +21,7 @@
 
 #endregion
 
+using System;
 using Gremlin.Net.Process.Traversal;
 using Xunit;
 
@@ -83,5 +84,15 @@
             Assert.Equal(5, clone.Bytecode.StepInstructions.Count);
             Assert.Equal(4, cloneClone.Bytecode.StepInstructions.Count);
         }
+        
+        [Fact]
+        public void ShouldOnlyAllowChildTraversalsThatAreAnonymous()
+        {
+            var g = AnonymousTraversalSource.Traversal();
+
+            g.V(0).AddE("self").To(__.V(1));
+
+            Assert.Throws<ArgumentException>(() => g.V(0).AddE("self").To(g.V(1)));
+        }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Process/Traversal/Strategy/StrategyTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Process/Traversal/Strategy/StrategyTests.cs
index fcb7cc3..039b7a1 100644
--- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Process/Traversal/Strategy/StrategyTests.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Process/Traversal/Strategy/StrategyTests.cs
@@ -128,11 +128,12 @@
 
     internal class TestStrategy : AbstractTraversalStrategy
     {
-        public TestStrategy()
+        public TestStrategy() : base("test.package." + nameof(TestStrategy))
         {
         }
 
         public TestStrategy(string configKey, dynamic configValue)
+            : this()
         {
             Configuration[configKey] = configValue;
         }
diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Process/Traversal/TraversalTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Process/Traversal/TraversalTests.cs
index a7d62ac..e773f74 100644
--- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Process/Traversal/TraversalTests.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Process/Traversal/TraversalTests.cs
@@ -24,7 +24,6 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
-using Moq;
 using Xunit;
 using Gremlin.Net.Process.Traversal;
 
@@ -180,16 +179,5 @@
             var expectedObjs = UnfoldBulks(objs, bulks);
             Assert.Equal(expectedObjs, traversedObjs);
         }
-
-        [Fact]
-        public void ShouldDisposeSideEffectsWhenDisposeIsCalled()
-        {
-            var sideEffectsMock = new Mock<ITraversalSideEffects>();
-            var traversal = new TestTraversal(new List<object>()) {SideEffects = sideEffectsMock.Object};
-
-            traversal.Dispose();
-
-            sideEffectsMock.Verify(m => m.Dispose());
-        }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphBinary/GraphBinaryMessageSerializerTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphBinary/GraphBinaryMessageSerializerTests.cs
new file mode 100644
index 0000000..83e7a87
--- /dev/null
+++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphBinary/GraphBinaryMessageSerializerTests.cs
@@ -0,0 +1,74 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System;
+using System.Threading.Tasks;
+using Gremlin.Net.Driver.Messages;
+using Gremlin.Net.Structure.IO.GraphBinary;
+using Xunit;
+
+namespace Gremlin.Net.UnitTest.Structure.IO.GraphBinary
+{
+    public class GraphBinaryMessageSerializerTests
+    {
+        [Fact]
+        public async Task ShouldSerializeRequestMessageToExpectedGraphBinary()
+        {
+            var expected = new byte[]
+            {
+                // header length
+                0x20, 
+                // header: application/vnd.graphbinary-v1.0
+                0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e,
+                0x67, 0x72, 0x61, 0x70, 0x68, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x2d, 0x76, 0x31, 0x2e, 0x30,
+                // version
+                0x81,
+                // uuid
+                0x40, 0x05, 0xb3, 0x74, 0xb1, 0x21, 0x40, 0x1b, 0x91, 0x57, 0xab, 0x1f, 0x1e, 0xcc, 0x89, 0x4e,
+                // op length
+                0x00, 0x00, 0x00, 0x04,
+                // op: "eval"
+                0x65, 0x76, 0x61, 0x6c,
+                // processor length
+                0x00, 0x00, 0x00, 0x00,
+                // args, map
+                    // length
+                    0x00, 0x00, 0x00, 0x01,
+                    // key type: string
+                    0x03,
+                    // key length: 
+                    0x00, 0x00, 0x00, 0x00, 0x07, 0x67, 0x72, 0x65, 0x6d, 0x6c, 0x69, 0x6e, 0x03, 0x00, 0x00, 0x00, 0x00, 0x11,
+                    0x27, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x27, 0x20, 0x2b, 0x20, 0x27, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x27
+            };
+            var msg = RequestMessage.Build("eval").OverrideRequestId(Guid.Parse("4005b374-b121-401b-9157-ab1f1ecc894e"))
+                .AddArgument("gremlin", "'Hello' + 'World'").Create();
+
+            var serializer = new GraphBinaryMessageSerializer();
+
+            var actual = await serializer.SerializeMessageAsync(msg);
+
+
+            Assert.Equal(expected, actual);
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphBinary/GraphBinaryTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphBinary/GraphBinaryTests.cs
new file mode 100644
index 0000000..7978005
--- /dev/null
+++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphBinary/GraphBinaryTests.cs
@@ -0,0 +1,888 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Numerics;
+using System.Threading.Tasks;
+using Gremlin.Net.Process.Traversal;
+using Gremlin.Net.Process.Traversal.Strategy.Decoration;
+using Gremlin.Net.Structure;
+using Gremlin.Net.Structure.IO.GraphBinary;
+using Xunit;
+using Path = Gremlin.Net.Structure.Path;
+
+namespace Gremlin.Net.UnitTest.Structure.IO.GraphBinary
+{
+    public class GraphBinaryTests
+    {
+        [Fact]
+        public async Task TestNull()
+        {
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(null, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Null(actual);
+        }
+    
+        [Fact]
+        public async Task TestInt()
+        {
+            const int expected = 100;
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+
+        [Theory]
+        [InlineData(1, new byte[]{0x00, 0x00, 0x00, 0x01})]
+        [InlineData(257, new byte[]{0x00, 0x00, 0x01, 0x01})]
+        [InlineData(-1, new byte[]{0xFF, 0xFF, 0xFF, 0xFF})]
+        [InlineData(-2, new byte[]{0xFF, 0xFF, 0xFF, 0xFE})]
+        public async Task TestIntSpec(int value, byte[] expected)
+        {
+            var writer = CreateGraphBinaryWriter();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteValueAsync(value, serializationStream, false);
+
+            var serBytes = serializationStream.ToArray();
+            Assert.Equal(expected, serBytes);
+        }
+        
+        [Fact]
+        public async Task TestLong()
+        {
+            const long expected = 100;
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        [Theory]
+        [InlineData(100.01f)]
+        [InlineData(float.NaN)]
+        [InlineData(float.NegativeInfinity)]
+        [InlineData(float.PositiveInfinity)]
+        public async Task TestFloat(float expected)
+        {
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        [Fact]
+        public async Task TestDouble()
+        {
+            const double expected = 100.001;
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        [Fact]
+        public async Task TestShort()
+        {
+            const short expected = 100;
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        [Fact]
+        public async Task TestDate()
+        {
+            var expected = DateTimeOffset.ParseExact("2016-12-14 16:14:36.295000", "yyyy-MM-dd HH:mm:ss.ffffff",
+                CultureInfo.InvariantCulture);
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        // TODO: Test timestamp, problem: same C# as for date
+
+        [Fact]
+        public async Task TestString()
+        {
+            const string expected = "serialize this!";
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        [Theory]
+        [InlineData("serialize this!", "serialize that!", "serialize that!", "stop telling me what to serialize")]
+        [InlineData(1, 2, 3, 4, 5)]
+        [InlineData(0.1, 1.1, 2.5, double.NaN)]
+        [InlineData(0.1f, 1.1f, 2.5f, float.NaN)]
+        public async Task TestHomogeneousList(params object[] listMembers)
+        {
+            var expected = new List<object>(listMembers);
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        [Fact]
+        public async Task TestHomogeneousTypeSafeList()
+        {
+            var expected = new List<string> {"test", "123"};
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        [Fact]
+        public async Task TestHeterogeneousList()
+        {
+            var expected = new List<object>
+                {"serialize this!", 0, "serialize that!", "serialize that!", 1, "stop telling me what to serialize", 2};
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+
+        [Fact]
+        public async Task TestArray()
+        {
+            var expected = new string[] {"hallo", "welt"};
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        [Theory]
+        [InlineData("serialize this!", "serialize that!", "serialize that!", "stop telling me what to serialize")]
+        [InlineData(1, 2, 3, 4, 5)]
+        [InlineData(0.1, 1.1, 2.5, double.NaN)]
+        [InlineData(0.1f, 1.1f, 2.5f, float.NaN)]
+        public async Task TestHomogeneousSet(params object[] listMembers)
+        {
+            var expected = new HashSet<object>(listMembers);
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        [Fact]
+        public async Task TestHomogeneousTypeSafeSet()
+        {
+            var expected = new HashSet<string> {"test", "123"};
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteValueAsync(expected, serializationStream, false);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadValueAsync<HashSet<string>>(serializationStream, false);
+            
+            Assert.Equal(expected, actual);
+            Assert.Equal(expected.GetType(), actual.GetType());
+        }
+        
+        [Fact]
+        public async Task TestHeterogeneousSet()
+        {
+            var expected = new HashSet<object>
+                {"serialize this!", 0, "serialize that!", "serialize that!", 1, "stop telling me what to serialize", 2};
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+
+        [Fact]
+        public async Task TestDictionary()
+        {
+            var expected = new Dictionary<object, object>
+            {
+                {"yo", "what"},
+                {"go", "no!"},
+                {"number", 123},
+                {321, "crazy with the number for a key"},
+                {987, new List<object> {"go", "deep", new Dictionary<object, object> {{"here", "!"}}}}
+            };
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        [Fact]
+        public async Task TestHomogeneousTypeSafeDictionary()
+        {
+            var expected = new Dictionary<string, int>
+            {
+                {"number", 123},
+                {"and", 456},
+                {"nothing else", 789}
+            };
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        [Fact]
+        public async Task TestHomogeneousTypeSafeDictionaryWithCorrectTyping()
+        {
+            var expected = new Dictionary<string, int>
+            {
+                {"number", 123},
+                {"and", 456},
+                {"nothing else", 789}
+            };
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteValueAsync(expected, serializationStream, false);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadValueAsync<Dictionary<string, int>>(serializationStream, false);
+            
+            Assert.Equal(expected, actual);
+            Assert.Equal(expected.GetType(), actual.GetType());
+        }
+        
+        [Fact]
+        public async Task TestGuid()
+        {
+            var expected = Guid.Parse("41d2e28a-20a4-4ab0-b379-d810dede3786");
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+
+        [Fact]
+        public async Task TestGuidSerialization()
+        {
+            var toSerialize = Guid.Parse("00112233-4455-6677-8899-aabbccddeeff");
+            var writer = CreateGraphBinaryWriter();
+            var serializationStream = new MemoryStream();
+
+            await writer.WriteValueAsync(toSerialize, serializationStream, false);
+
+            var expected = new byte[]
+                {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
+            Assert.Equal(expected, serializationStream.ToArray());
+        }
+
+        [Fact]
+        public async Task TestVertex()
+        {
+            var expected = new Vertex(123, "person");
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        [Fact]
+        public async Task TestVertexWithNullLabel()
+        {
+            var expected = new Vertex(123, null);
+            var writer = CreateGraphBinaryWriter();
+            var serializationStream = new MemoryStream();
+            
+            await Assert.ThrowsAsync<IOException>(() => writer.WriteAsync(expected, serializationStream));
+        }
+        
+        [Fact]
+        public async Task TestEdge()
+        {
+            var expected = new Edge(123, new Vertex(1, "person"), "developed", new Vertex(10, "software"));
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+
+        [Fact]
+        public async Task TestPath()
+        {
+            var expected =
+                new Path(
+                    new List<ISet<string>>
+                        {new HashSet<string> {"a", "b"}, new HashSet<string> {"c", "d"}, new HashSet<string> {"e"}},
+                    new List<object> {1, 2, 3});
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+
+        [Fact]
+        public async Task TestProperty()
+        {
+            var expected = new Property("name", "stephen", null);
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        [Fact]
+        public async Task TestVertexProperty()
+        {
+            var expected = new VertexProperty(123, "name", "stephen", null);
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        [Fact]
+        public async Task TestBarrier()
+        {
+            var expected = Barrier.NormSack;
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        [Fact]
+        public async Task TestCardinality()
+        {
+            var expected = Cardinality.Set;
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        [Fact]
+        public async Task TestColumn()
+        {
+            var expected = Column.Values;
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        [Fact]
+        public async Task TestDirection()
+        {
+            var expected = Direction.Out;
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        [Fact]
+        public async Task TestOperator()
+        {
+            var expected = Operator.Min;
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        [Fact]
+        public async Task TestOrder()
+        {
+            var expected = Order.Shuffle;
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        [Fact]
+        public async Task TestPick()
+        {
+            var expected = Pick.None;
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        [Fact]
+        public async Task TestPop()
+        {
+            var expected = Pop.All;
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        [Fact]
+        public async Task TestScope()
+        {
+            var expected = Scope.Local;
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        [Fact]
+        public async Task TestT()
+        {
+            var expected = T.Label;
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        [Fact]
+        public async Task TestBinding()
+        {
+            var expected = new Binding("name", "marko");
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        [Fact]
+        public async Task TestBytecode()
+        {
+            var expected = new Bytecode();
+            expected.SourceInstructions.Add(new Instruction("withStrategies", "SubgraphStrategy"));
+            expected.StepInstructions.Add(new Instruction("V", 1, 2, 3));
+            expected.StepInstructions.Add(new Instruction("out"));
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = (Bytecode) await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected.SourceInstructions, actual.SourceInstructions);
+            Assert.Equal(expected.StepInstructions, actual.StepInstructions);
+        }
+        
+        [Theory]
+        [InlineData(1)]
+        [InlineData(123)]
+        public async Task TestByte(byte expected)
+        {
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        [Fact]
+        public async Task TestByteBuffer()
+        {
+            var expected = new byte[] {1, 2, 3};
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        [Theory]
+        [InlineData(true)]
+        [InlineData(false)]
+        public async Task TestBoolean(bool expected)
+        {
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        [Theory]
+        [InlineData('a')]
+        [InlineData('0')]
+        [InlineData('¢')]
+        [InlineData('€')]
+        public async Task TestChar(char expected)
+        {
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        [Fact]
+        public async Task TestDuration()
+        {
+            var expected = new TimeSpan(1, 2, 3, 4, 5);
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        [Fact]
+        public async Task TestBigInteger()
+        {
+            var expected = BigInteger.Parse("123456789987654321123456789987654321");
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        [Theory]
+        [InlineData("190.035")]
+        [InlineData("0.19")]
+        [InlineData("1900")]
+        [InlineData("-1900")]
+        [InlineData("100000000000000")]
+        [InlineData("100000000000000000000000000")]
+        public async Task TestBigDecimal(string decimalValue)
+        {
+            var expected = Decimal.Parse(decimalValue);
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected, actual);
+        }
+        
+        [Fact]
+        public async Task TestLambda()
+        {
+            var expected = Lambda.Groovy("some expression");
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = (StringBasedLambda) await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected.Language, actual.Language);
+            Assert.Equal(expected.LambdaExpression, actual.LambdaExpression);
+            Assert.Equal(expected.Arguments, actual.Arguments);
+        }
+        
+        [Fact]
+        public async Task TestPBetween()
+        {
+            var expected = P.Between(1, 2);
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = (P) await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected.OperatorName, actual.OperatorName);
+            Assert.Equal(expected.Other, actual.Other);
+            Assert.Equal(expected.Value, actual.Value);
+        }
+        
+        [Fact]
+        public async Task TestPGt()
+        {
+            var expected = P.Gt(5);
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = (P) await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected.OperatorName, actual.OperatorName);
+            Assert.Equal(expected.Other, actual.Other);
+            Assert.Equal(expected.Value, actual.Value);
+        }
+
+        [Fact]
+        public async Task TestPAnd()
+        {
+            var expected = P.Not(P.Lte(10).And(P.Not(P.Between(11, 20)))).And(P.Lt(29).Or(P.Eq(35)));
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = (P) await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected.ToString(), actual.ToString());
+        }
+        
+        [Fact]
+        public async Task TestTextP()
+        {
+            var expected = TextP.Containing("o");
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = (TextP) await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected.OperatorName, actual.OperatorName);
+            Assert.Equal(expected.Other, actual.Other);
+            Assert.Equal(expected.Value, actual.Value);
+        }
+        
+        [Fact]
+        public async Task TestTraverser()
+        {
+            var expected = new Traverser("test", 3);
+            var writer = CreateGraphBinaryWriter();
+            var reader = CreateGraphBinaryReader();
+            var serializationStream = new MemoryStream();
+            
+            await writer.WriteAsync(expected, serializationStream);
+            serializationStream.Position = 0;
+            var actual = (Traverser) await reader.ReadAsync(serializationStream);
+            
+            Assert.Equal(expected.Object, actual.Object);
+            Assert.Equal(expected.Bulk, actual.Bulk);
+        }
+        
+        private static GraphBinaryWriter CreateGraphBinaryWriter()
+        {
+            return new GraphBinaryWriter();
+        }
+        
+        private static GraphBinaryReader CreateGraphBinaryReader()
+        {
+            return new GraphBinaryReader();
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/BytecodeGraphSONSerializerTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/BytecodeGraphSONSerializerTests.cs
index 9b39391..ad78334 100644
--- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/BytecodeGraphSONSerializerTests.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/BytecodeGraphSONSerializerTests.cs
@@ -1,4 +1,4 @@
-#region License
+#region License
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -22,7 +22,6 @@
 #endregion
 
 using System.Collections.Generic;
-using System.Numerics;
 using Gremlin.Net.Process.Traversal;
 using Gremlin.Net.Structure.IO.GraphSON;
 using Xunit;
@@ -162,6 +161,7 @@
         public TestTraversal(Bytecode bytecode)
         {
             Bytecode = bytecode;
+            IsAnonymous = true;
         }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs
index 3a49143..d50da9c 100644
--- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs
@@ -24,11 +24,11 @@
 using System;
 using System.Collections.Generic;
 using System.Numerics;
+using System.Text.Json;
 using Gremlin.Net.Process.Traversal;
 using Gremlin.Net.Structure;
 using Gremlin.Net.Structure.IO.GraphSON;
 using Moq;
-using Newtonsoft.Json.Linq;
 using Xunit;
 
 namespace Gremlin.Net.UnitTest.Structure.IO.GraphSON
@@ -61,17 +61,6 @@
             return new GraphSON2Reader();
         }
 
-        //During CI, we encountered a case where Newtonsoft.Json version 9.0.0
-        //was loaded although there is no obvious direct nor indirect dependency
-        //on that version of the library. An explicit reference to version
-        //11.0.0 from Gremlin.Net.UnitTest fixes that, however, it is
-        //still unclear what causes the downgrade. Until resolution, we keep this test.
-        [Fact]
-        public void NewtonsoftJsonVersionShouldSupportReallyBigIntegers()
-        {
-            Assert.Equal(new Version(11, 0, 0, 0), typeof(JToken).Assembly.GetName().Version);
-        }
-
         [Fact]
         public void ShouldDeserializeWithCustomDeserializerForNewType()
         {
@@ -80,259 +69,297 @@
                 {"NS:TestClass", new TestGraphSONDeserializer()}
             };
             var reader = new GraphSON2Reader(deserializerByGraphSONType);
-            var graphSON = "{\"@type\":\"NS:TestClass\",\"@value\":\"test\"}";
-
-            var jObject = JObject.Parse(graphSON);
-            var readObj = reader.ToObject(jObject);
-
-            Assert.Equal("test", readObj.Value);
+            const string graphSON = "{\"@type\":\"NS:TestClass\",\"@value\":\"test\"}";
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(graphSON);
+            var deserializedValue = reader.ToObject(jsonElement);
+        
+            Assert.Equal("test", deserializedValue.Value);
         }
-
+        
         [Fact]
         public void ShouldDeserializeWithCustomDeserializerForCommonType()
         {
             var customSerializerMock = new Mock<IGraphSONDeserializer>();
-            var overrideTypeString = "g:Int64";
+            const string overrideTypeString = "g:Int64";
             var customSerializerByType = new Dictionary<string, IGraphSONDeserializer>
             {
                 {overrideTypeString, customSerializerMock.Object}
             };
             var reader = new GraphSON2Reader(customSerializerByType);
 
+            var jsonElement =
+                JsonSerializer.Deserialize<JsonElement>($"{{\"@type\":\"{overrideTypeString}\",\"@value\":12}}");
+            var deserializedValue = reader.ToObject(jsonElement);
 
-            reader.ToObject(JObject.Parse($"{{\"@type\":\"{overrideTypeString}\",\"@value\":12}}"));
-
-            customSerializerMock.Verify(m => m.Objectify(It.IsAny<JToken>(), It.IsAny<GraphSONReader>()));
+            customSerializerMock.Verify(m => m.Objectify(It.IsAny<JsonElement>(), It.IsAny<GraphSONReader>()));
         }
-
+        
         [Theory, MemberData(nameof(Versions))]
         public void ShouldDeserializeDateToDateTimeOffset(int version)
         {
-            var graphSon = "{\"@type\":\"g:Date\",\"@value\":1475583442552}";
+            const string graphSon = "{\"@type\":\"g:Date\",\"@value\":1475583442552}";
             var reader = CreateStandardGraphSONReader(version);
-
-            DateTimeOffset deserializedValue = reader.ToObject(JObject.Parse(graphSon));
-
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(graphSon);
+            var deserializedValue = reader.ToObject(jsonElement);
+        
             var expectedDateTimeOffset = TestUtils.FromJavaTime(1475583442552);
             Assert.Equal(expectedDateTimeOffset, deserializedValue);
         }
-
+        
         [Theory, MemberData(nameof(Versions))]
         public void ShouldDeserializeDictionary(int version)
         {
-            var serializedDict = "{\"age\":[{\"@type\":\"g:Int32\",\"@value\":29}],\"name\":[\"marko\"]}";
+            const string serializedDict = "{\"age\":[{\"@type\":\"g:Int32\", \"@value\":29}], \"name\":[\"marko\"], " +
+                                          "\"gender\": null}";
             var reader = CreateStandardGraphSONReader(version);
-
-            var jObject = JObject.Parse(serializedDict);
-            var deserializedDict = reader.ToObject(jObject);
-
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(serializedDict);
+            var deserializedValue = reader.ToObject(jsonElement);
+        
             var expectedDict = new Dictionary<string, dynamic>
             {
                 {"age", new List<object> {29}},
-                {"name", new List<object> {"marko"}}
+                {"name", new List<object> {"marko"}},
+                {"gender", null}
             };
-            Assert.Equal(expectedDict, deserializedDict);
+            Assert.Equal(expectedDict, deserializedValue);
         }
-
+        
         [Theory, MemberData(nameof(Versions))]
         public void ShouldDeserializeEdge(int version)
         {
-            var graphSon =
-                "{\"@type\":\"g:Edge\", \"@value\":{\"id\":{\"@type\":\"g:Int64\",\"@value\":17},\"label\":\"knows\",\"inV\":\"x\",\"outV\":\"y\",\"inVLabel\":\"xLab\",\"properties\":{\"aKey\":\"aValue\",\"bKey\":true}}}";
+            const string graphSon = "{\"@type\":\"g:Edge\", \"@value\":{\"id\":{\"@type\":\"g:Int64\", \"@value\":17}, " +
+                                    "\"label\":\"knows\", \"inV\":\"x\", \"outV\":\"y\", \"inVLabel\":\"xLab\", " +
+                                    "\"properties\":{\"aKey\":\"aValue\", \"bKey\":true}}}";
             var reader = CreateStandardGraphSONReader(version);
-
-            Edge readEdge = reader.ToObject(JObject.Parse(graphSon));
-
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(graphSon);
+            Edge readEdge = reader.ToObject(jsonElement);
+        
             Assert.Equal((long) 17, readEdge.Id);
             Assert.Equal("knows", readEdge.Label);
             Assert.Equal(new Vertex("x", "xLabel"), readEdge.InV);
             Assert.Equal(new Vertex("y"), readEdge.OutV);
         }
-
+        
         [Theory, MemberData(nameof(Versions))]
         public void ShouldDeserializeInt(int version)
         {
             var serializedValue = "{\"@type\":\"g:Int32\",\"@value\":5}";
             var reader = CreateStandardGraphSONReader(version);
 
-            var jObject = JObject.Parse(serializedValue);
-            var deserializedValue = reader.ToObject(jObject);
-
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(serializedValue);
+            var deserializedValue = reader.ToObject(jsonElement);
+        
             Assert.Equal(5, deserializedValue);
         }
-
+        
         [Theory, MemberData(nameof(Versions))]
         public void ShouldDeserializeLong(int version)
         {
-            var serializedValue = "{\"@type\":\"g:Int64\",\"@value\":5}";
+            const string serializedValue = "{\"@type\":\"g:Int64\",\"@value\":5}";
             var reader = CreateStandardGraphSONReader(version);
-
-            var jObject = JObject.Parse(serializedValue);
-            var deserializedValue = reader.ToObject(jObject);
-
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(serializedValue);
+            var deserializedValue = reader.ToObject(jsonElement);
+        
             Assert.Equal((long) 5, deserializedValue);
         }
-
+        
         [Theory, MemberData(nameof(Versions))]
         public void ShouldDeserializeFloat(int version)
         {
-            var serializedValue = "{\"@type\":\"g:Float\",\"@value\":31.3}";
+            const string serializedValue = "{\"@type\":\"g:Float\",\"@value\":31.3}";
             var reader = CreateStandardGraphSONReader(version);
-
-            var jObject = JObject.Parse(serializedValue);
-            var deserializedValue = reader.ToObject(jObject);
-
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(serializedValue);
+            var deserializedValue = reader.ToObject(jsonElement);
+        
             Assert.Equal((float) 31.3, deserializedValue);
         }
-
+        
         [Theory, MemberData(nameof(Versions))]
         public void ShouldDeserializeDouble(int version)
         {
-            var serializedValue = "{\"@type\":\"g:Double\",\"@value\":31.2}";
+            const string serializedValue = "{\"@type\":\"g:Double\",\"@value\":31.2}";
             var reader = CreateStandardGraphSONReader(version);
-
-            var jObject = JObject.Parse(serializedValue);
-            var deserializedValue = reader.ToObject(jObject);
-
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(serializedValue);
+            var deserializedValue = reader.ToObject(jsonElement);
+        
             Assert.Equal(31.2, deserializedValue);
         }
-
+        
         [Theory, MemberData(nameof(Versions))]
         public void ShouldDeserializeNaN(int version)
         {
-            var serializedValue = "{\"@type\":\"g:Double\",\"@value\":'NaN'}";
+            const string serializedValue = "{\"@type\":\"g:Double\",\"@value\":\"NaN\"}";
             var reader = CreateStandardGraphSONReader(version);
-
-            var jObject = JObject.Parse(serializedValue);
-            var deserializedValue = reader.ToObject(jObject);
-
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(serializedValue);
+            var deserializedValue = reader.ToObject(jsonElement);
+        
             Assert.Equal(Double.NaN, deserializedValue);
         }
-
+        
         [Theory, MemberData(nameof(Versions))]
         public void ShouldDeserializePositiveInfinity(int version)
         {
-            var serializedValue = "{\"@type\":\"g:Double\",\"@value\":'Infinity'}";
+            const string serializedValue = "{\"@type\":\"g:Double\",\"@value\":\"Infinity\"}";
             var reader = CreateStandardGraphSONReader(version);
-
-            var jObject = JObject.Parse(serializedValue);
-            var deserializedValue = reader.ToObject(jObject);
-
-            Assert.Equal(Double.PositiveInfinity, deserializedValue);
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(serializedValue);
+            var deserializedValue = reader.ToObject(jsonElement);
+        
+            Assert.Equal(double.PositiveInfinity, deserializedValue);
         }
-
+        
         [Theory, MemberData(nameof(Versions))]
         public void ShouldDeserializeNegativeInfinity(int version)
         {
-            var serializedValue = "{\"@type\":\"g:Double\",\"@value\":'-Infinity'}";
+            const string serializedValue = "{\"@type\":\"g:Double\",\"@value\":\"-Infinity\"}";
             var reader = CreateStandardGraphSONReader(version);
-
-            var jObject = JObject.Parse(serializedValue);
-            var deserializedValue = reader.ToObject(jObject);
-
-            Assert.Equal(Double.NegativeInfinity, deserializedValue);
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(serializedValue);
+            var deserializedValue = reader.ToObject(jsonElement);
+        
+            Assert.Equal(double.NegativeInfinity, deserializedValue);
         }
-
+        
         [Theory, MemberData(nameof(Versions))]
         public void ShouldDeserializeDecimal(int version)
         {
-            var serializedValue = "{\"@type\":\"gx:BigDecimal\",\"@value\":-8.201}";
+            const string serializedValue = "{\"@type\":\"gx:BigDecimal\",\"@value\":-8.201}";
             var reader = CreateStandardGraphSONReader(version);
-
-            var jObject = JObject.Parse(serializedValue);
-            decimal deserializedValue = reader.ToObject(jObject);
-
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(serializedValue);
+            var deserializedValue = reader.ToObject(jsonElement);
+        
             Assert.Equal(-8.201M, deserializedValue);
         }
-
+        
         [Theory, MemberData(nameof(Versions))]
         public void ShouldDeserializeDecimalValueAsString(int version)
         {
-            var serializedValue = "{\"@type\":\"gx:BigDecimal\",\"@value\":\"7.50\"}";
+            const string serializedValue = "{\"@type\":\"gx:BigDecimal\",\"@value\":\"7.50\"}";
             var reader = CreateStandardGraphSONReader(version);
-
-            var jObject = JObject.Parse(serializedValue);
-            decimal deserializedValue = reader.ToObject(jObject);
-
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(serializedValue);
+            decimal deserializedValue = reader.ToObject(jsonElement);
+        
             Assert.Equal(7.5M, deserializedValue);
         }
-
+        
+        [Theory, MemberData(nameof(Versions))]
+        public void ShouldDeserializeByte(int version)
+        {
+            const string serializedValue = "{\"@type\":\"gx:Byte\",\"@value\":1}";
+            var reader = CreateStandardGraphSONReader(version);
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(serializedValue);
+            var deserializedValue = reader.ToObject(jsonElement);
+        
+            Assert.Equal(1, deserializedValue);
+        }
+        
+        [Theory, MemberData(nameof(Versions))]
+        public void ShouldDeserializeChar(int version)
+        {
+            const string serializedValue = "{\"@type\":\"gx:Char\",\"@value\":\"x\"}";
+            var reader = CreateStandardGraphSONReader(version);
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(serializedValue);
+            var deserializedValue = reader.ToObject(jsonElement);
+        
+            Assert.Equal('x', deserializedValue);
+        }
+        
         [Theory, MemberData(nameof(Versions))]
         public void ShouldDeserializeList(int version)
         {
-            var serializedValue = "[{\"@type\":\"g:Int32\",\"@value\":5},{\"@type\":\"g:Int32\",\"@value\":6}]";
+            const string serializedValue = "[{\"@type\":\"g:Int32\", \"@value\":5}, {\"@type\":\"g:Int32\", " +
+                                           "\"@value\":6}, null]";
             var reader = CreateStandardGraphSONReader(version);
-
-            var jObject = JArray.Parse(serializedValue);
-            var deserializedValue = reader.ToObject(jObject);
-
-            Assert.Equal(new List<object> {5, 6}, deserializedValue);
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(serializedValue);
+            var deserializedValue = reader.ToObject(jsonElement);
+        
+            Assert.Equal(new List<object> {5, 6, null}, deserializedValue);
         }
-
+        
         [Theory, MemberData(nameof(Versions))]
         public void ShouldDeserializeT(int version)
         {
-            var graphSon = "{\"@type\":\"g:T\",\"@value\":\"label\"}";
+            const string graphSon = "{\"@type\":\"g:T\",\"@value\":\"label\"}";
             var reader = CreateStandardGraphSONReader(version);
-
-            T readT = reader.ToObject(JObject.Parse(graphSon));
-
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(graphSon);
+            T readT = reader.ToObject(jsonElement);
+        
             Assert.Equal(T.Label, readT);
         }
-
+        
         [Theory, MemberData(nameof(Versions))]
         public void ShouldDeserializeDirection(int version)
         {
-            var serializedValue = "{\"@type\":\"g:Direction\",\"@value\":\"OUT\"}";
+            const string serializedValue = "{\"@type\":\"g:Direction\",\"@value\":\"OUT\"}";
             var reader = CreateStandardGraphSONReader(version);
-
-            var jObject = JObject.Parse(serializedValue);
-            var deserializedValue = reader.ToObject(jObject);
-
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(serializedValue);
+            var deserializedValue = reader.ToObject(jsonElement);
+        
             Assert.Equal(Direction.Out, deserializedValue);
         }
-
+        
         [Fact]
         public void ShouldDeserializePathFromGraphSON2()
         {
-            var graphSon =
+            const string graphSon =
                 "{\"@type\":\"g:Path\",\"@value\":{\"labels\":[[\"a\"],[\"b\",\"c\"],[]],\"objects\":[{\"@type\":\"g:Vertex\",\"@value\":{\"id\":{\"@type\":\"g:Int32\",\"@value\":1},\"label\":\"person\",\"properties\":{\"name\":[{\"@type\":\"g:VertexProperty\",\"@value\":{\"id\":{\"@type\":\"g:Int64\",\"@value\":0},\"value\":\"marko\",\"label\":\"name\"}}],\"age\":[{\"@type\":\"g:VertexProperty\",\"@value\":{\"id\":{\"@type\":\"g:Int64\",\"@value\":1},\"value\":{\"@type\":\"g:Int32\",\"@value\":29},\"label\":\"age\"}}]}}},{\"@type\":\"g:Vertex\",\"@value\":{\"id\":{\"@type\":\"g:Int32\",\"@value\":3},\"label\":\"software\",\"properties\":{\"name\":[{\"@type\":\"g:VertexProperty\",\"@value\":{\"id\":{\"@type\":\"g:Int64\",\"@value\":4},\"value\":\"lop\",\"label\":\"name\"}}],\"lang\":[{\"@type\":\"g:VertexProperty\",\"@value\":{\"id\":{\"@type\":\"g:Int64\",\"@value\":5},\"value\":\"java\",\"label\":\"lang\"}}]}}},\"lop\"]}}";
             var reader = CreateStandardGraphSONReader(2);
-
-            Path readPath = reader.ToObject(JObject.Parse(graphSon));
-
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(graphSon);
+            Path readPath = reader.ToObject(jsonElement);
+        
             Assert.Equal("path[v[1], v[3], lop]", readPath.ToString());
             Assert.Equal(new Vertex(1), readPath[0]);
             Assert.Equal(new Vertex(1), readPath["a"]);
             Assert.Equal("lop", readPath[2]);
             Assert.Equal(3, readPath.Count);
         }
-
+        
         [Fact]
         public void ShouldDeserializePathFromGraphSON3()
         {
-            var graphSon = "{\"@type\":\"g:Path\",\"@value\":{" +
-                           "\"labels\":{\"@type\":\"g:List\",\"@value\":[{\"@type\":\"g:Set\",\"@value\":[\"z\"]}]}," +
-                           "\"objects\":{\"@type\":\"g:List\",\"@value\":[{\"@type\":\"g:Vertex\",\"@value\":{\"id\":{\"@type\":\"g:Int64\",\"@value\":5},\"label\":\"\"}}]}}}";
+            const string graphSon = "{\"@type\":\"g:Path\",\"@value\":{" +
+                                    "\"labels\":{\"@type\":\"g:List\",\"@value\":[{\"@type\":\"g:Set\",\"@value\":[\"z\"]}]}," +
+                                    "\"objects\":{\"@type\":\"g:List\",\"@value\":[{\"@type\":\"g:Vertex\",\"@value\":{\"id\":{\"@type\":\"g:Int64\",\"@value\":5},\"label\":\"\"}}]}}}";
             var reader = CreateStandardGraphSONReader(3);
-
-            Path readPath = reader.ToObject(JObject.Parse(graphSon));
-
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(graphSon);
+            Path readPath = reader.ToObject(jsonElement);
+        
             Assert.Equal("path[v[5]]", readPath.ToString());
             Assert.Equal(new Vertex(5L), readPath[0]);
             Assert.Equal(new Vertex(5L), readPath["z"]);
             Assert.Equal(1, readPath.Count);
         }
-
+        
         [Theory, MemberData(nameof(Versions))]
         public void ShouldDeserializePropertyWithEdgeElement(int version)
         {
-            var graphSon =
-                "{\"@type\":\"g:Property\",\"@value\":{\"key\":\"aKey\",\"value\":{\"@type\":\"g:Int64\",\"@value\":17},\"element\":{\"@type\":\"g:Edge\",\"@value\":{\"id\":{\"@type\":\"g:Int64\",\"@value\":122},\"label\":\"knows\",\"inV\":\"x\",\"outV\":\"y\",\"inVLabel\":\"xLab\"}}}}";
+            const string graphSon = "{\"@type\":\"g:Property\", \"@value\":{\"key\":\"aKey\", " +
+                                    "\"value\":{\"@type\":\"g:Int64\", \"@value\":17}, " +
+                                    "\"element\":{\"@type\":\"g:Edge\", \"@value\":{\"id\":{\"@type\":\"g:Int64\", " +
+                                    "\"@value\":122}, \"label\":\"knows\", \"inV\":\"x\", \"outV\":\"y\", " +
+                                    "\"inVLabel\":\"xLab\"}}}}";
             var reader = CreateStandardGraphSONReader(version);
-
-            Property readProperty = reader.ToObject(JObject.Parse(graphSon));
-
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(graphSon);
+            Property readProperty = reader.ToObject(jsonElement);
+        
             Assert.Equal("aKey", readProperty.Key);
             Assert.Equal((long) 17, readProperty.Value);
             Assert.Equal(typeof(Edge), readProperty.Element.GetType());
@@ -342,265 +369,285 @@
             Assert.Equal("x", edge.InV.Id);
             Assert.Equal("y", edge.OutV.Id);
         }
-
+        
         [Theory, MemberData(nameof(Versions))]
         public void ShouldDeserializeTimestampToDateTimeOffset(int version)
         {
-            var graphSon = "{\"@type\":\"g:Timestamp\",\"@value\":1475583442558}";
+            const string graphSon = "{\"@type\":\"g:Timestamp\",\"@value\":1475583442558}";
             var reader = CreateStandardGraphSONReader(version);
-
-            DateTimeOffset deserializedValue = reader.ToObject(JObject.Parse(graphSon));
-
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(graphSon);
+            var deserializedValue = reader.ToObject(jsonElement);
+        
             var expectedDateTimeOffset = TestUtils.FromJavaTime(1475583442558);
             Assert.Equal(expectedDateTimeOffset, deserializedValue);
         }
-
+        
         [Theory, MemberData(nameof(Versions))]
         public void ShouldDeserializeGuid(int version)
         {
-            var graphSon = "{\"@type\":\"g:UUID\",\"@value\":\"41d2e28a-20a4-4ab0-b379-d810dede3786\"}";
+            const string graphSon = "{\"@type\":\"g:UUID\",\"@value\":\"41d2e28a-20a4-4ab0-b379-d810dede3786\"}";
             var reader = CreateStandardGraphSONReader(version);
-
-            Guid readGuid = reader.ToObject(JObject.Parse(graphSon));
-
-            Assert.Equal(Guid.Parse("41d2e28a-20a4-4ab0-b379-d810dede3786"), readGuid);
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(graphSon);
+            var deserializedValue = reader.ToObject(jsonElement);
+        
+            Assert.Equal(Guid.Parse("41d2e28a-20a4-4ab0-b379-d810dede3786"), deserializedValue);
         }
-
+        
         [Theory, MemberData(nameof(Versions))]
         public void ShouldDeserializeVertexProperty(int version)
         {
-            var graphSon =
-                "{\"@type\":\"g:VertexProperty\",\"@value\":{\"id\":\"anId\",\"label\":\"aKey\",\"value\":true,\"vertex\":{\"@type\":\"g:Int32\",\"@value\":9}}}";
+            const string graphSon = "{\"@type\":\"g:VertexProperty\", \"@value\":{\"id\":\"anId\", \"label\":\"aKey\", " +
+                                    "\"value\":true, \"vertex\":{\"@type\":\"g:Int32\", \"@value\":9}}}";
             var reader = CreateStandardGraphSONReader(version);
-
-            VertexProperty readVertexProperty = reader.ToObject(JObject.Parse(graphSon));
-
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(graphSon);
+            VertexProperty readVertexProperty = reader.ToObject(jsonElement);
+        
             Assert.Equal("anId", readVertexProperty.Id);
             Assert.Equal("aKey", readVertexProperty.Label);
             Assert.True(readVertexProperty.Value);
             Assert.NotNull(readVertexProperty.Vertex);
         }
-
+        
         [Theory, MemberData(nameof(Versions))]
         public void ShouldDeserializeVertexPropertyWithLabel(int version)
         {
-            var graphSon =
-                "{\"@type\":\"g:VertexProperty\", \"@value\":{\"id\":{\"@type\":\"g:Int32\",\"@value\":1},\"label\":\"name\",\"value\":\"marko\"}}";
+            const string graphSon = "{\"@type\":\"g:VertexProperty\", \"@value\":{\"id\":{\"@type\":\"g:Int32\", " +
+                                    "\"@value\":1}, \"label\":\"name\", \"value\":\"marko\"}}";
             var reader = CreateStandardGraphSONReader(version);
-
-            VertexProperty readVertexProperty = reader.ToObject(JObject.Parse(graphSon));
-
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(graphSon);
+            VertexProperty readVertexProperty = reader.ToObject(jsonElement);
+        
             Assert.Equal(1, readVertexProperty.Id);
             Assert.Equal("name", readVertexProperty.Label);
             Assert.Equal("marko", readVertexProperty.Value);
             Assert.Null(readVertexProperty.Vertex);
         }
-
+        
         [Theory, MemberData(nameof(Versions))]
         public void ShouldDeserializeVertex(int version)
         {
-            var graphSon = "{\"@type\":\"g:Vertex\", \"@value\":{\"id\":{\"@type\":\"g:Float\",\"@value\":45.23}}}";
+            const string graphSon = "{\"@type\":\"g:Vertex\", \"@value\":{\"id\":{\"@type\":\"g:Float\", " +
+                                    "\"@value\":45.23}}}";
             var reader = CreateStandardGraphSONReader(version);
-
-            var readVertex = reader.ToObject(JObject.Parse(graphSon));
-
-            Assert.Equal(new Vertex(45.23f), readVertex);
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(graphSon);
+            var deserializedValue = reader.ToObject(jsonElement);
+        
+            Assert.Equal(new Vertex(45.23f), deserializedValue);
         }
-
+        
+        [Theory, MemberData(nameof(Versions))]
+        public void ShouldDeserializeVertexWithLabel(int version)
+        {
+            const string graphSon = "{\"@type\":\"g:Vertex\", \"@value\":{\"id\":{\"@type\":\"g:Float\", " +
+                                    "\"@value\":45.23}, \"label\": \"person\"}}";
+            var reader = CreateStandardGraphSONReader(version);
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(graphSon);
+            Vertex deserializedValue = reader.ToObject(jsonElement);
+        
+            Assert.Equal("person", deserializedValue.Label);
+        }
+        
         [Theory, MemberData(nameof(Versions))]
         public void ShouldDeserializeVertexWithEdges(int version)
         {
-            var graphSon =
+            const string graphSon =
                 "{\"@type\":\"g:Vertex\", \"@value\":{\"id\":{\"@type\":\"g:Int32\",\"@value\":1},\"label\":\"person\",\"outE\":{\"created\":[{\"id\":{\"@type\":\"g:Int32\",\"@value\":9},\"inV\":{\"@type\":\"g:Int32\",\"@value\":3},\"properties\":{\"weight\":{\"@type\":\"g:Double\",\"@value\":0.4}}}],\"knows\":[{\"id\":{\"@type\":\"g:Int32\",\"@value\":7},\"inV\":{\"@type\":\"g:Int32\",\"@value\":2},\"properties\":{\"weight\":{\"@type\":\"g:Double\",\"@value\":0.5}}},{\"id\":{\"@type\":\"g:Int32\",\"@value\":8},\"inV\":{\"@type\":\"g:Int32\",\"@value\":4},\"properties\":{\"weight\":{\"@type\":\"g:Double\",\"@value\":1.0}}}]},\"properties\":{\"name\":[{\"id\":{\"@type\":\"g:Int64\",\"@value\":0},\"value\":\"marko\"}],\"age\":[{\"id\":{\"@type\":\"g:Int64\",\"@value\":1},\"value\":{\"@type\":\"g:Int32\",\"@value\":29}}]}}}";
             var reader = CreateStandardGraphSONReader(version);
-
-            var readVertex = reader.ToObject(JObject.Parse(graphSon));
-
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(graphSon);
+            Vertex readVertex = reader.ToObject(jsonElement);
+        
             Assert.Equal(new Vertex(1), readVertex);
             Assert.Equal("person", readVertex.Label);
             Assert.Equal(typeof(int), readVertex.Id.GetType());
         }
-
+        
         [Theory, MemberData(nameof(VersionsSupportingCollections))]
         public void ShouldDeserializeEmptyGList(int version)
         {
-            var graphSon =
-                "{\"@type\":\"g:List\", \"@value\": []}";
+            const string graphSon = "{\"@type\":\"g:List\", \"@value\": []}";
             var reader = CreateStandardGraphSONReader(version);
-
-            var deserializedValue = reader.ToObject(JObject.Parse(graphSon));
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(graphSon);
+            var deserializedValue = reader.ToObject(jsonElement);
+            
             Assert.Equal(new object[0], deserializedValue);
         }
-
+        
         [Theory, MemberData(nameof(VersionsSupportingCollections))]
         public void ShouldDeserializeGList(int version)
         {
             const string json = "{\"@type\":\"g:List\", \"@value\": [{\"@type\": \"g:Int32\", \"@value\": 1}," +
                                 "{\"@type\": \"g:Int32\", \"@value\": 2}, {\"@type\": \"g:Int32\", \"@value\": 3}]}";
             var reader = CreateStandardGraphSONReader(version);
-
-            var deserializedValue = reader.ToObject(JObject.Parse(json));
-
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(json);
+            var deserializedValue = reader.ToObject(jsonElement);
+        
             Assert.Equal((IList<object>)new object[] { 1, 2, 3}, deserializedValue);
         }
-
+        
         [Theory, MemberData(nameof(VersionsSupportingCollections))]
         public void ShouldDeserializeGSet(int version)
         {
-            const string json = "{\"@type\":\"g:Set\", \"@value\": [{\"@type\": \"g:Int32\", \"@value\": 1}," +
-                                "{\"@type\": \"g:Int32\", \"@value\": 2}, {\"@type\": \"g:Int32\", \"@value\": 3}]}";
+            const string graphSon = "{\"@type\":\"g:Set\", \"@value\": [{\"@type\": \"g:Int32\", \"@value\": 1}," +
+                                    "{\"@type\": \"g:Int32\", \"@value\": 2}, {\"@type\": \"g:Int32\", \"@value\": 3}]}";
             var reader = CreateStandardGraphSONReader(version);
-
-            var deserializedValue = reader.ToObject(JObject.Parse(json));
-
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(graphSon);
+            var deserializedValue = reader.ToObject(jsonElement);
+        
             Assert.Equal((ISet<object>)new HashSet<object>{ 1, 2, 3}, deserializedValue);
         }
-
+        
         [Theory, MemberData(nameof(VersionsSupportingCollections))]
         public void ShouldDeserializeGMap(int version)
         {
             const string json = "{\"@type\":\"g:Map\", \"@value\": [\"a\",{\"@type\": \"g:Int32\", \"@value\": 1}, " +
                                 "\"b\", {\"@type\": \"g:Int32\", \"@value\": 2}]}";
             var reader = CreateStandardGraphSONReader(version);
-
-            var deserializedValue = reader.ToObject(JObject.Parse(json));
-
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(json);
+            var deserializedValue = reader.ToObject(jsonElement);
+        
             Assert.Equal(new Dictionary<object, object>{ { "a", 1 }, { "b", 2 }}, deserializedValue);
         }
-
+        
+        [Theory, MemberData(nameof(VersionsSupportingCollections))]
+        public void ShouldDeserializeGMapWithNonStringKeys(int version)
+        {
+            const string json = "{\"@type\":\"g:Map\", \"@value\": [{\"@type\":\"g:Int32\", \"@value\":123}, \"red\"]}";
+            var reader = CreateStandardGraphSONReader(version);
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(json);
+            var deserializedValue = reader.ToObject(jsonElement);
+        
+            Assert.Equal(new Dictionary<object, object>{ { 123, "red" }}, deserializedValue);
+        }
+        
         [Theory, MemberData(nameof(VersionsSupportingCollections))]
         public void ShouldDeserializeBulkSet(int version)
         {
-            const string json = "{\"@type\": \"g:BulkSet\", \"@value\": [" +
-                                "\"marko\", {\"@type\": \"g:Int64\", \"@value\": 1}, " +
-                                "\"josh\", {\"@type\": \"g:Int64\", \"@value\": 3}]}";
+            const string graphSon = "{\"@type\": \"g:BulkSet\", \"@value\": [" +
+                                    "\"marko\", {\"@type\": \"g:Int64\", \"@value\": 1}, " +
+                                    "\"josh\", {\"@type\": \"g:Int64\", \"@value\": 3}]}";
             var reader = CreateStandardGraphSONReader(version);
-
-            var deserializedValue = reader.ToObject(JObject.Parse(json));
-
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(graphSon);
+            var deserializedValue = reader.ToObject(jsonElement);
+        
             Assert.Equal(new List<object>{ "marko", "josh", "josh", "josh" }, deserializedValue);
         }
-
+        
         [Fact]
         public void ShouldDeserializeBulkSetWithGraphSON3()
         {
-            const string json =
+            const string graphSon =
                 "{\"@type\":\"g:List\",\"@value\":[{\"@type\":\"g:Traverser\",\"@value\":{\"bulk\":{\"@type\":\"g:Int64\",\"@value\":1},\"value\":{\"@type\":\"g:BulkSet\",\"@value\":[{\"@type\":\"g:Int64\",\"@value\":1},{\"@type\":\"g:Int64\",\"@value\":2},{\"@type\":\"g:Int64\",\"@value\":0},{\"@type\":\"g:Int64\",\"@value\":3},{\"@type\":\"g:Int64\",\"@value\":2},{\"@type\":\"g:Int64\",\"@value\":1},{\"@type\":\"g:Double\",\"@value\":1.0},{\"@type\":\"g:Int64\",\"@value\":2}]}}}]}";
             var reader = CreateStandardGraphSONReader(3);
-            var deserializedValue = reader.ToObject(JObject.Parse(json));
+            
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(graphSon);
+            var deserializedValue = reader.ToObject(jsonElement);
         }
-
-        [Fact]
-        public void ShouldDeserializeTraverser()
+        
+        [Theory, MemberData(nameof(VersionsSupportingCollections))]
+        public void ShouldDeserializeTraverser(int version)
         {
-            dynamic d = JObject.Parse("{\"@type\":\"g:Traverser\",\"@value\":1,\"bulk\": {\"type\":\"g:Int64\",\"value\":10}}");
-
-            Assert.NotNull(d);
-            Assert.Equal("g:Traverser", (string)d["@type"]);
+            const string json = "{\"@type\":\"g:Traverser\", \"@value\":{\"bulk\":{\"@type\":\"g:Int64\", " +
+                                "\"@value\":10}, \"value\":{\"@type\":\"g:Int32\", \"@value\":1}}}";
+            var reader = CreateStandardGraphSONReader(version);
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(json);
+            Traverser deserializedValue = reader.ToObject(jsonElement);
+            
+            Assert.Equal(10, deserializedValue.Bulk);
+            Assert.Equal(1, deserializedValue.Object);
         }
-
+        
         [Theory, MemberData(nameof(Versions))]
         public void ShouldDeserializeDurationToTimeSpan(int version)
         {
-            var serializedValue = "{\"@type\":\"gx:Duration\",\"@value\":\"PT120H\"}";
+            const string graphSon = "{\"@type\":\"gx:Duration\",\"@value\":\"PT120H\"}";
             var reader = CreateStandardGraphSONReader(version);
-
-            var jObject = JObject.Parse(serializedValue);
-            TimeSpan deserializedValue = reader.ToObject(jObject);
-
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(graphSon);
+            var deserializedValue = reader.ToObject(jsonElement);
+        
             Assert.Equal(TimeSpan.FromDays(5), deserializedValue);
         }
-
+        
         [Theory, MemberData(nameof(Versions))]
         public void ShouldDeserializeBigInteger(int version)
         {
-            var serializedValue = "{\"@type\":\"gx:BigInteger\",\"@value\":123456789}";
+            var graphSon = "{\"@type\":\"gx:BigInteger\",\"@value\":123456789}";
             var reader = CreateStandardGraphSONReader(version);
-
-            var jObject = JObject.Parse(serializedValue);
-            BigInteger deserializedValue = reader.ToObject(jObject);
-
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(graphSon);
+            var deserializedValue = reader.ToObject(jsonElement);
+        
             Assert.Equal(BigInteger.Parse("123456789"), deserializedValue);
         }
-
+        
         [Theory, MemberData(nameof(Versions))]
         public void ShouldDeserializeBigIntegerValueAsString(int version)
         {
-            var serializedValue = "{\"@type\":\"gx:BigInteger\",\"@value\":\"123456789\"}";
+            var graphSon = "{\"@type\":\"gx:BigInteger\", \"@value\":\"123456789\"}";
             var reader = CreateStandardGraphSONReader(version);
-
-            var jObject = JObject.Parse(serializedValue);
-            BigInteger deserializedValue = reader.ToObject(jObject);
-
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(graphSon);
+            var deserializedValue = reader.ToObject(jsonElement);
+        
             Assert.Equal(BigInteger.Parse("123456789"), deserializedValue);
         }
-
+        
         [Theory, MemberData(nameof(Versions))]
         public void ShouldDeserializeReallyBigIntegerValue(int version)
         {
-            var serializedValue = "{\"@type\":\"gx:BigInteger\",\"@value\":123456789987654321123456789987654321}";
+            const string graphSon = "{\"@type\":\"gx:BigInteger\", \"@value\":123456789987654321123456789987654321}";
             var reader = CreateStandardGraphSONReader(version);
-
-            var jObject = JObject.Parse(serializedValue);
-            BigInteger deserializedValue = reader.ToObject(jObject);
-
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(graphSon);
+            var deserializedValue = reader.ToObject(jsonElement);
+        
             Assert.Equal(BigInteger.Parse("123456789987654321123456789987654321"), deserializedValue);
         }
-
-        [Theory, MemberData(nameof(Versions))]
-        public void ShouldDeserializeByte(int version)
-        {
-            var serializedValue = "{\"@type\":\"gx:Byte\",\"@value\":1}";
-            var reader = CreateStandardGraphSONReader(version);
-
-            var jObject = JObject.Parse(serializedValue);
-            var deserializedValue = reader.ToObject(jObject);
-
-            Assert.Equal(1, deserializedValue);
-        }
-
+        
         [Theory, MemberData(nameof(Versions))]
         public void ShouldDeserializeByteBuffer(int version)
         {
-            var serializedValue = "{\"@type\":\"gx:ByteBuffer\",\"@value\":\"c29tZSBieXRlcyBmb3IgeW91\"}";
+            const string graphSon = "{\"@type\":\"gx:ByteBuffer\", \"@value\":\"c29tZSBieXRlcyBmb3IgeW91\"}";
             var reader = CreateStandardGraphSONReader(version);
-
-            var jObject = JObject.Parse(serializedValue);
-            var deserializedValue = reader.ToObject(jObject);
-
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(graphSon);
+            var deserializedValue = reader.ToObject(jsonElement);
+        
             Assert.Equal(Convert.FromBase64String("c29tZSBieXRlcyBmb3IgeW91"), deserializedValue);
         }
-
-        [Theory, MemberData(nameof(Versions))]
-        public void ShouldDeserializeChar(int version)
-        {
-            var serializedValue = "{\"@type\":\"gx:Char\",\"@value\":\"x\"}";
-            var reader = CreateStandardGraphSONReader(version);
-
-            var jObject = JObject.Parse(serializedValue);
-            var deserializedValue = reader.ToObject(jObject);
-
-            Assert.Equal('x', deserializedValue);
-        }
-
+        
         [Theory, MemberData(nameof(Versions))]
         public void ShouldDeserializeInt16(int version)
         {
-            var serializedValue = "{\"@type\":\"gx:Int16\",\"@value\":100}";
+            const string graphSon = "{\"@type\":\"gx:Int16\", \"@value\":100}";
             var reader = CreateStandardGraphSONReader(version);
-
-            var jObject = JObject.Parse(serializedValue);
-            var deserializedValue = reader.ToObject(jObject);
-
+        
+            var jsonElement = JsonSerializer.Deserialize<JsonElement>(graphSon);
+            var deserializedValue = reader.ToObject(jsonElement);
+        
             Assert.Equal(100, deserializedValue);
         }
     }
 
     internal class TestGraphSONDeserializer : IGraphSONDeserializer
     {
-        public dynamic Objectify(JToken graphsonObject, GraphSONReader reader)
+        public dynamic Objectify(JsonElement graphsonObject, GraphSONReader reader)
         {
-            return new TestClass {Value = graphsonObject.ToString()};
+            return new TestClass {Value = graphsonObject.GetString()};
         }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONWriterTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONWriterTests.cs
index 409776b..ce593f7 100644
--- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONWriterTests.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONWriterTests.cs
@@ -203,6 +203,8 @@
         public void ShouldSerializeWithCustomSerializerForCommonType()
         {
             var customSerializerMock = new Mock<IGraphSONSerializer>();
+            customSerializerMock.Setup(m => m.Dictify(It.IsAny<int>(), It.IsAny<GraphSONWriter>()))
+                .Returns(new Dictionary<string, dynamic>());
             var customSerializerByType = new Dictionary<Type, IGraphSONSerializer>
             {
                 {typeof(int), customSerializerMock.Object}
@@ -282,12 +284,12 @@
         public void ShouldSerializeGList(int version)
         {
             var writer = CreateGraphSONWriter(version);
-            var list = new List<object> {5, 6};
+            var list = new List<object> {5, 6, null};
 
             var serializedGraphSON = writer.WriteObject(list);
 
             var expectedGraphSON = "{\"@type\":\"g:List\",\"@value\":[{\"@type\":\"g:Int32\",\"@value\":5}," +
-                                   "{\"@type\":\"g:Int32\",\"@value\":6}]}";
+                                   "{\"@type\":\"g:Int32\",\"@value\":6},null]}";
             Assert.Equal(expectedGraphSON, serializedGraphSON);
         }
 
diff --git a/gremlin-dotnet/test/pom.xml b/gremlin-dotnet/test/pom.xml
index b37bef1..74687ad 100644
--- a/gremlin-dotnet/test/pom.xml
+++ b/gremlin-dotnet/test/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.apache.tinkerpop</groupId>
         <artifactId>gremlin-dotnet</artifactId>
-        <version>3.4.12-SNAPSHOT</version>
+        <version>3.5.1-SNAPSHOT</version>
     </parent>
     <artifactId>gremlin-dotnet-tests</artifactId>
     <name>Apache TinkerPop :: Gremlin.Net - Tests</name>
@@ -103,25 +103,49 @@
                         <artifactId>gmavenplus-plugin</artifactId>
                         <dependencies>
                             <dependency>
-                                <groupId>log4j</groupId>
-                                <artifactId>log4j</artifactId>
-                                <version>1.2.17</version>
-                                <scope>runtime</scope>
-                            </dependency>
-                            <dependency>
                                 <groupId>org.apache.tinkerpop</groupId>
                                 <artifactId>gremlin-server</artifactId>
                                 <version>${project.version}</version>
+                            </dependency>
+                            <dependency>
+                                <groupId>org.apache.tinkerpop</groupId>
+                                <artifactId>gremlin-test</artifactId>
+                                <version>${project.version}</version>
+                            </dependency>
+                            <dependency>
+                                <groupId>log4j</groupId>
+                                <artifactId>log4j</artifactId>
+                                <version>${log4j.version}</version>
                                 <scope>runtime</scope>
                             </dependency>
                             <dependency>
                                 <groupId>org.codehaus.groovy</groupId>
-                                <artifactId>groovy-ant</artifactId>
+                                <artifactId>groovy-all</artifactId>
                                 <version>${groovy.version}</version>
+                                <type>pom</type>
+                                <scope>runtime</scope>
                             </dependency>
                         </dependencies>
                         <executions>
                             <execution>
+                                <id>generate-radish-support</id>
+                                <phase>generate-sources</phase>
+                                <goals>
+                                    <goal>execute</goal>
+                                </goals>
+                                <configuration>
+                                    <properties>
+                                        <property>
+                                            <name>projectBaseDir</name>
+                                            <value>${project.basedir}/../../</value>
+                                        </property>
+                                    </properties>
+                                    <scripts>
+                                        <script>${project.basedir}/../build/generate.groovy</script>
+                                    </scripts>
+                                </configuration>
+                            </execution>
+                            <execution>
                                 <id>gremlin-server-start</id>
                                 <phase>pre-integration-test</phase>
                                 <goals>
@@ -134,10 +158,6 @@
                                             <value>${skipTests}</value>
                                         </property>
                                         <property>
-                                            <name>python</name>
-                                            <value>false</value>
-                                        </property>
-                                        <property>
                                             <name>gremlinServerDir</name>
                                             <value>${gremlin.server.dir}</value>
                                         </property>
diff --git a/gremlin-driver/pom.xml b/gremlin-driver/pom.xml
index 9aee47f..e606620 100644
--- a/gremlin-driver/pom.xml
+++ b/gremlin-driver/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.apache.tinkerpop</groupId>
         <artifactId>tinkerpop</artifactId>
-        <version>3.4.12-SNAPSHOT</version>
+        <version>3.5.1-SNAPSHOT</version>
     </parent>
     <artifactId>gremlin-driver</artifactId>
     <name>Apache TinkerPop :: Gremlin Driver</name>
@@ -41,6 +41,7 @@
             <artifactId>groovy</artifactId>
             <version>${groovy.version}</version>
             <classifier>indy</classifier>
+            <optional>true</optional>
         </dependency>
         <dependency>
             <groupId>org.codehaus.groovy</groupId>
@@ -54,6 +55,7 @@
                     <artifactId>groovy</artifactId>
                 </exclusion>
             </exclusions>
+            <optional>true</optional>
         </dependency>
         <dependency>
             <groupId>org.apache.commons</groupId>
@@ -100,12 +102,12 @@
         </dependency>
         <dependency>
             <groupId>org.powermock</groupId>
-            <artifactId>powermock-api-mockito</artifactId>
+            <artifactId>powermock-api-mockito2</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.hamcrest</groupId>
-            <artifactId>hamcrest-all</artifactId>
+            <artifactId>hamcrest</artifactId>
             <scope>test</scope>
         </dependency>
     </dependencies>
@@ -151,6 +153,107 @@
             </plugin>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                        <configuration>
+                            <shadeSourcesContent>true</shadeSourcesContent>
+                            <createSourcesJar>true</createSourcesJar>
+                            <shadedArtifactAttached>true</shadedArtifactAttached>
+                            <shadedClassifierName>shaded</shadedClassifierName>
+                            <artifactSet>
+                                <!-- exclude logging stuff from uberjar - shading prevents proper logger initialization -->
+                                <!-- exclude groovy as it's only needed for json serialization and is an optional dependency -->
+                                <excludes>
+                                    <exclude>log4j:log4j</exclude>
+                                    <exclude>org.slf4j:slf4j-log4j12</exclude>
+                                    <exclude>org.slf4j:slf4j-api</exclude>
+                                    <exclude>org.slf4j:jcl-over-slf4j</exclude>
+                                    <exclude>org.codehaus.groovy:groovy</exclude>
+                                    <exclude>org.codehaus.groovy:groovy-json</exclude>
+                                </excludes>
+                            </artifactSet>
+                            <relocations>
+                                <relocation>
+                                    <pattern>com.carrotsearch</pattern>
+                                    <shadedPattern>com.shaded.carrotsearch</shadedPattern>
+                                </relocation>
+                                <relocation>
+                                    <pattern>com.jcabi</pattern>
+                                    <shadedPattern>com.shaded.jcabi</shadedPattern>
+                                </relocation>
+                                <relocation>
+                                    <pattern>com.squareup</pattern>
+                                    <shadedPattern>com.shaded.squareup</shadedPattern>
+                                </relocation>
+                                <relocation>
+                                    <pattern>io.netty</pattern>
+                                    <shadedPattern>io.shaded.netty</shadedPattern>
+                                </relocation>
+                                <relocation>
+                                    <pattern>net.objecthunter</pattern>
+                                    <shadedPattern>net.shaded.carrotsearch</shadedPattern>
+                                </relocation>
+                                <relocation>
+                                    <pattern>org.apache.commons</pattern>
+                                    <shadedPattern>org.shaded.apache.commons</shadedPattern>
+                                </relocation>
+                                <relocation>
+                                    <pattern>org.javatuples</pattern>
+                                    <shadedPattern>org.shaded.javatuples</shadedPattern>
+                                </relocation>
+                                <relocation>
+                                    <pattern>org.yaml</pattern>
+                                    <shadedPattern>org.shaded.yaml</shadedPattern>
+                                </relocation>
+                            </relocations>
+                            <transformers>
+                                <transformer implementation="org.apache.maven.plugins.shade.resource.ApacheLicenseResourceTransformer"/>
+                                <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
+                                <transformer implementation="org.apache.maven.plugins.shade.resource.DontIncludeResourceTransformer">
+                                    <resources>
+                                        <resource>LICENSE.txt</resource>
+                                        <resource>LICENSE</resource>
+                                        <resource>NOTICE.txt</resource>
+                                        <resource>NOTICE</resource>
+                                        <resource>licenses</resource>
+                                    </resources>
+                                </transformer>
+                                <transformer implementation="org.apache.maven.plugins.shade.resource.IncludeResourceTransformer">
+                                    <resource>META-INF/LICENSE</resource>
+                                    <file>src/main/static/LICENSE</file>
+                                </transformer>
+                                <transformer implementation="org.apache.maven.plugins.shade.resource.IncludeResourceTransformer">
+                                    <resource>META-INF/NOTICE</resource>
+                                    <file>src/main/static/NOTICE</file>
+                                </transformer>
+                                <transformer implementation="org.apache.maven.plugins.shade.resource.IncludeResourceTransformer">
+                                    <resource>META-INF/licenses/jcabi-log</resource>
+                                    <file>src/main/static/licenses/jcabi-log</file>
+                                </transformer>
+                                <transformer implementation="org.apache.maven.plugins.shade.resource.IncludeResourceTransformer">
+                                    <resource>META-INF/licenses/jcabi-manifests</resource>
+                                    <file>src/main/static/licenses/jcabi-manifests</file>
+                                </transformer>
+                                <transformer implementation="org.apache.maven.plugins.shade.resource.IncludeResourceTransformer">
+                                    <resource>META-INF/licenses/kryo</resource>
+                                    <file>src/main/static/licenses/kryo</file>
+                                </transformer>
+                                <transformer implementation="org.apache.maven.plugins.shade.resource.IncludeResourceTransformer">
+                                    <resource>META-INF/licenses/minlog</resource>
+                                    <file>src/main/static/licenses/minlog</file>
+                                </transformer>
+                            </transformers>>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-surefire-plugin</artifactId>
             </plugin>
             <plugin>
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Channelizer.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Channelizer.java
index b0f43b8..bccf947 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Channelizer.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Channelizer.java
@@ -18,27 +18,24 @@
  */
 package org.apache.tinkerpop.gremlin.driver;
 
-import io.netty.channel.Channel;
-import io.netty.handler.codec.http.EmptyHttpHeaders;
-import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
-
 import org.apache.tinkerpop.gremlin.driver.exception.ConnectionException;
-import org.apache.tinkerpop.gremlin.driver.handler.NioGremlinRequestEncoder;
-import org.apache.tinkerpop.gremlin.driver.handler.NioGremlinResponseDecoder;
 import org.apache.tinkerpop.gremlin.driver.handler.WebSocketClientHandler;
 import org.apache.tinkerpop.gremlin.driver.handler.WebSocketGremlinRequestEncoder;
 import org.apache.tinkerpop.gremlin.driver.handler.WebSocketGremlinResponseDecoder;
+import io.netty.channel.Channel;
 import io.netty.channel.ChannelHandler;
 import io.netty.channel.ChannelInitializer;
 import io.netty.channel.ChannelPipeline;
 import io.netty.channel.socket.SocketChannel;
+import io.netty.handler.codec.http.EmptyHttpHeaders;
+import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
 import io.netty.handler.codec.http.HttpClientCodec;
 import io.netty.handler.codec.http.HttpObjectAggregator;
 import io.netty.handler.codec.http.websocketx.WebSocketVersion;
 import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketClientCompressionHandler;
 import io.netty.handler.ssl.SslContext;
 import io.netty.handler.timeout.IdleStateHandler;
-import org.apache.tinkerpop.gremlin.driver.simple.WebSocketClient;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -72,29 +69,6 @@
     public void close(final Channel channel);
 
     /**
-     * Create a message for the driver to use as a "keep-alive" for the connection. This method will only be used if
-     * {@link #supportsKeepAlive()} is {@code true}.
-     *
-     * @deprecated As of release 3.4.9, not directly replaced. Any keep-alive functionality should be implemented as
-     * a function of the configured channel and not as a component of the {@code Channelizer} itself.
-     */
-    @Deprecated
-    public default Object createKeepAliveMessage() {
-        return null;
-    }
-
-    /**
-     * Determines if the channelizer supports a method for keeping the connection to the server alive.
-     *
-     * @deprecated As of release 3.4.9, not directly replaced. Any keep-alive functionality should be implemented as
-     * a function of the configured channel and not as a component of the {@code Channelizer} itself.
-     */
-    @Deprecated
-    public default boolean supportsKeepAlive() {
-        return false;
-    }
-
-    /**
      * Called after the channel connects. The {@code Channelizer} may need to perform some functions, such as a
      * handshake.
      */
@@ -176,30 +150,6 @@
         }
 
         /**
-         * Keep-alive is supported through the ping/pong websocket protocol.
-         *
-         * @see <a href=https://tools.ietf.org/html/rfc6455#section-5.5.2>IETF RFC 6455</a>
-         * @deprecated As of release 3.4.9, not directly replaced. The keep-alive functionality is delegated to Netty
-         * {@code IdleStateHandler} which is added to the pipeline in {@link Channelizer}.
-         */
-        @Deprecated
-        @Override
-        public boolean supportsKeepAlive() {
-            return true;
-        }
-
-        /**
-         * @deprecated As of release 3.4.9, not directly replaced. The keep-alive functionality is delegated to Netty
-         * {@code IdleStateHandler} which is added to the pipeline in {@link Channelizer}.
-         */
-        @Deprecated
-        @Override
-        public Object createKeepAliveMessage() {
-            throw new UnsupportedOperationException(
-                    "WebSocketChannelizer uses Netty's IdleStateHandler to send keep alive ping frames to the server.");
-        }
-
-        /**
          * Sends a {@code CloseWebSocketFrame} to the server for the specified channel.
          */
         @Override
@@ -234,7 +184,8 @@
                             EmptyHttpHeaders.INSTANCE, maxContentLength, true, false, -1,
                             cluster.getHandshakeInterceptor()), cluster.getConnectionSetupTimeout());
 
-            final int keepAliveInterval = toIntExact(TimeUnit.SECONDS.convert(cluster.connectionPoolSettings().keepAliveInterval, TimeUnit.MILLISECONDS));
+            final int keepAliveInterval = toIntExact(TimeUnit.SECONDS.convert(
+                    cluster.connectionPoolSettings().keepAliveInterval, TimeUnit.MILLISECONDS));
 
             pipeline.addLast("http-codec", new HttpClientCodec());
             pipeline.addLast("aggregator", new HttpObjectAggregator(maxContentLength));
@@ -269,23 +220,4 @@
             }
         }
     }
-
-    /**
-     * NIO {@link Channelizer} implementation.
-     *
-     * @deprecated As of release 3.3.10, not replaced, use {@link WebSocketClient}.
-     */
-    @Deprecated
-    public final class NioChannelizer extends AbstractChannelizer {
-        @Override
-        public void init(final Connection connection) {
-            super.init(connection);
-        }
-
-        @Override
-        public void configure(ChannelPipeline pipeline) {
-            pipeline.addLast("gremlin-decoder", new NioGremlinResponseDecoder(cluster.getSerializer()));
-            pipeline.addLast("gremlin-encoder", new NioGremlinRequestEncoder(true, cluster.getSerializer()));
-        }
-    }
 }
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java
index eae1da8..43c9936 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java
@@ -350,7 +350,7 @@
                 .add(Tokens.ARGS_BATCH_SIZE, batchSize);
 
         // apply settings if they were made available
-        options.getTimeout().ifPresent(timeout -> request.add(Tokens.ARGS_SCRIPT_EVAL_TIMEOUT, timeout));
+        options.getTimeout().ifPresent(timeout -> request.add(Tokens.ARGS_EVAL_TIMEOUT, timeout));
         options.getParameters().ifPresent(params -> request.addArg(Tokens.ARGS_BINDINGS, params));
         options.getAliases().ifPresent(aliases -> request.addArg(Tokens.ARGS_ALIASES, aliases));
         options.getOverrideRequestId().ifPresent(request::overrideRequestId);
@@ -363,7 +363,7 @@
      * A low-level method that allows the submission of a manually constructed {@link RequestMessage}.
      */
     public CompletableFuture<ResultSet> submitAsync(final RequestMessage msg) {
-        if (isClosing()) throw new IllegalStateException("Client has been closed");
+        if (isClosing()) throw new IllegalStateException("Client is closed");
 
         if (!initialized)
             init();
@@ -604,7 +604,7 @@
 
                 // apply settings if they were made available
                 options.getBatchSize().ifPresent(batchSize -> request.add(Tokens.ARGS_BATCH_SIZE, batchSize));
-                options.getTimeout().ifPresent(timeout -> request.add(Tokens.ARGS_SCRIPT_EVAL_TIMEOUT, timeout));
+                options.getTimeout().ifPresent(timeout -> request.add(Tokens.ARGS_EVAL_TIMEOUT, timeout));
                 options.getOverrideRequestId().ifPresent(request::overrideRequestId);
                 options.getUserAgent().ifPresent(userAgent -> request.add(Tokens.ARGS_USER_AGENT, userAgent));
 
@@ -670,19 +670,19 @@
             return client.chooseConnection(msg);
         }
 
-        /**
-         * Prevents messages from being sent from this {@code Client}. Note that calling this method does not call
-         * close on the {@code Client} that created it.
-         */
+        @Override
+        public void close() {
+            client.close();
+        }
+
         @Override
         public synchronized CompletableFuture<Void> closeAsync() {
-            close.complete(null);
-            return close;
+            return client.closeAsync();
         }
 
         @Override
         public boolean isClosing() {
-            return close.isDone();
+            return client.isClosing();
         }
 
         /**
@@ -703,6 +703,7 @@
     public final static class SessionedClient extends Client {
         private final String sessionId;
         private final boolean manageTransactions;
+        private final boolean maintainStateAfterException;
 
         private ConnectionPool connectionPool;
 
@@ -712,9 +713,13 @@
             super(cluster, settings);
             this.sessionId = settings.getSession().get().sessionId;
             this.manageTransactions = settings.getSession().get().manageTransactions;
+            this.maintainStateAfterException = settings.getSession().get().maintainStateAfterException;
         }
 
-        String getSessionId() {
+        /**
+         * Returns the session identifier bound to this {@code Client}.
+         */
+        public String getSessionId() {
             return sessionId;
         }
 
@@ -726,6 +731,7 @@
             builder.processor("session");
             builder.addArg(Tokens.ARGS_SESSION, sessionId);
             builder.addArg(Tokens.ARGS_MANAGE_TRANSACTION, manageTransactions);
+            builder.addArg(Tokens.ARGS_MAINTAIN_STATE_AFTER_EXCEPTION, maintainStateAfterException);
             return builder;
         }
 
@@ -850,11 +856,13 @@
         private final boolean manageTransactions;
         private final String sessionId;
         private final boolean forceClosed;
+        private final boolean maintainStateAfterException;
 
         private SessionSettings(final Builder builder) {
             manageTransactions = builder.manageTransactions;
             sessionId = builder.sessionId;
             forceClosed = builder.forceClosed;
+            maintainStateAfterException = builder.maintainStateAfterException;
         }
 
         /**
@@ -879,6 +887,10 @@
             return forceClosed;
         }
 
+        public boolean maintainStateAfterException() {
+            return maintainStateAfterException;
+        }
+
         public static SessionSettings.Builder build() {
             return new SessionSettings.Builder();
         }
@@ -887,11 +899,23 @@
             private boolean manageTransactions = false;
             private String sessionId = UUID.randomUUID().toString();
             private boolean forceClosed = false;
+            private boolean maintainStateAfterException = false;
 
             private Builder() {
             }
 
             /**
+             * When {@code true} an exception within a session will not close the session and remove the state bound to
+             * that session. This setting is for the {@code UnifiedChannelizer} and when set to {@code true} will allow
+             * sessions to behave similar to how they did under the {@code OpProcessor} approach original to Gremlin
+             * Server. By default this value is {@code false}.
+             */
+            public Builder maintainStateAfterException(final boolean maintainStateAfterException) {
+                this.maintainStateAfterException = maintainStateAfterException;
+                return this;
+            }
+
+            /**
              * If enabled, transactions will be "managed" such that each request will represent a complete transaction.
              * By default this value is {@code false}.
              */
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Cluster.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Cluster.java
index d08c89c..5a8c3ac 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Cluster.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Cluster.java
@@ -24,7 +24,7 @@
 import io.netty.handler.ssl.SslContextBuilder;
 import io.netty.handler.ssl.SslProvider;
 import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
 import org.apache.tinkerpop.gremlin.driver.ser.Serializers;
 import io.netty.bootstrap.Bootstrap;
@@ -181,11 +181,7 @@
                 .port(settings.port)
                 .path(settings.path)
                 .enableSsl(settings.connectionPool.enableSsl)
-                .trustCertificateChainFile(settings.connectionPool.trustCertChainFile)
                 .keepAliveInterval(settings.connectionPool.keepAliveInterval)
-                .keyCertChainFile(settings.connectionPool.keyCertChainFile)
-                .keyFile(settings.connectionPool.keyFile)
-                .keyPassword(settings.connectionPool.keyPassword)
                 .keyStore(settings.connectionPool.keyStore)
                 .keyStorePassword(settings.connectionPool.keyStorePassword)
                 .keyStoreType(settings.connectionPool.keyStoreType)
@@ -399,16 +395,6 @@
     }
 
     /**
-     * Gets how long a session will stay open assuming the current connection actually is configured for their use.
-     *
-     * @deprecated As of release 3.3.11, replaced in essence by {@link #getMaxWaitForClose()}.
-     */
-    @Deprecated
-    public int getMaxWaitForSessionClose() {
-        return manager.connectionPoolSettings.maxWaitForSessionClose;
-    }
-
-    /**
      * Gets how long a connection will wait for all pending messages to be returned from the server before closing.
      */
     public int getMaxWaitForClose() {
@@ -478,7 +464,7 @@
         return manager.factory;
     }
 
-    MessageSerializer getSerializer() {
+    MessageSerializer<?> getSerializer() {
         return manager.serializer;
     }
 
@@ -519,21 +505,6 @@
         final Settings.ConnectionPoolSettings connectionPoolSettings = connectionPoolSettings();
         final SslContextBuilder builder = SslContextBuilder.forClient();
 
-        if (connectionPoolSettings.trustCertChainFile != null) {
-            logger.warn("Using deprecated SSL trustCertChainFile support");
-            builder.trustManager(new File(connectionPoolSettings.trustCertChainFile));
-        }
-
-        if (null != connectionPoolSettings.keyCertChainFile && null != connectionPoolSettings.keyFile) {
-            logger.warn("Using deprecated SSL keyFile support");
-            final File keyCertChainFile = new File(connectionPoolSettings.keyCertChainFile);
-            final File keyFile = new File(connectionPoolSettings.keyFile);
-
-            // note that keyPassword may be null here if the keyFile is not
-            // password-protected.
-            builder.keyManager(keyCertChainFile, keyFile, connectionPoolSettings.keyPassword);
-        }
-
         // Build JSSE SSLContext
         try {
 
@@ -594,7 +565,7 @@
         private List<InetAddress> addresses = new ArrayList<>();
         private int port = 8182;
         private String path = "/gremlin";
-        private MessageSerializer serializer = null;
+        private MessageSerializer<?> serializer = null;
         private int nioPoolSize = Runtime.getRuntime().availableProcessors();
         private int workerPoolSize = Runtime.getRuntime().availableProcessors() * 2;
         private int minConnectionPoolSize = ConnectionPool.MIN_POOL_SIZE;
@@ -604,7 +575,6 @@
         private int maxInProcessPerConnection = Connection.MAX_IN_PROCESS;
         private int minInProcessPerConnection = Connection.MIN_IN_PROCESS;
         private int maxWaitForConnection = Connection.MAX_WAIT_FOR_CONNECTION;
-        private int maxWaitForSessionClose = Connection.MAX_WAIT_FOR_SESSION_CLOSE;
         private int maxWaitForClose = Connection.MAX_WAIT_FOR_CLOSE;
         private int maxContentLength = Connection.MAX_CONTENT_LENGTH;
         private int reconnectInterval = Connection.RECONNECT_INTERVAL;
@@ -612,10 +582,6 @@
         private long keepAliveInterval = Connection.KEEP_ALIVE_INTERVAL;
         private String channelizer = Channelizer.WebSocketChannelizer.class.getName();
         private boolean enableSsl = false;
-        private String trustCertChainFile = null;
-        private String keyCertChainFile = null;
-        private String keyFile = null;
-        private String keyPassword = null;
         private String keyStore = null;
         private String keyStorePassword = null;
         private String trustStore = null;
@@ -687,7 +653,7 @@
         /**
          * Sets the {@link MessageSerializer} to use.
          */
-        public Builder serializer(final MessageSerializer serializer) {
+        public Builder serializer(final MessageSerializer<?> serializer) {
             this.serializer = serializer;
             return this;
         }
@@ -713,20 +679,8 @@
         }
 
         /**
-         * File location for a SSL Certificate Chain to use when SSL is enabled. If this value is not provided and
-         * SSL is enabled, the default {@link TrustManager} will be used.
-         * @deprecated As of release 3.2.10, replaced by {@link #trustStore}
-         */
-        @Deprecated
-        public Builder trustCertificateChainFile(final String certificateChainFile) {
-            this.trustCertChainFile = certificateChainFile;
-            return this;
-        }
-
-        /**
-         * Length of time in milliseconds to wait on an idle connection before sending a keep-alive request. This
-         * setting is only relevant to {@link Channelizer} implementations that return {@code true} for
-         * {@link Channelizer#supportsKeepAlive()}.  Set to zero to disable this feature.
+         * Length of time in milliseconds to wait on an idle connection before sending a keep-alive request. Set to
+         * zero to disable this feature.
          */
         public Builder keepAliveInterval(final long keepAliveInterval) {
             this.keepAliveInterval = keepAliveInterval;
@@ -734,36 +688,6 @@
         }
 
         /**
-         * The X.509 certificate chain file in PEM format.
-         * @deprecated As of release 3.2.10, replaced by {@link #keyStore}
-         */
-        @Deprecated
-        public Builder keyCertChainFile(final String keyCertChainFile) {
-            this.keyCertChainFile = keyCertChainFile;
-            return this;
-        }
-
-        /**
-         * The PKCS#8 private key file in PEM format.
-         * @deprecated As of release 3.2.10, replaced by {@link #keyStore}
-         */
-        @Deprecated
-        public Builder keyFile(final String keyFile) {
-            this.keyFile = keyFile;
-            return this;
-        }
-
-        /**
-         * The password of the {@link #keyFile}, or {@code null} if it's not password-protected.
-         * @deprecated As of release 3.2.10, replaced by {@link #keyStorePassword}
-         */
-        @Deprecated
-        public Builder keyPassword(final String keyPassword) {
-            this.keyPassword = keyPassword;
-            return this;
-        }
-
-        /**
          * The file location of the private key in JKS or PKCS#12 format.
          */
         public Builder keyStore(final String keyStore) {
@@ -921,29 +845,9 @@
         }
 
         /**
-         * If the connection is using a "session" this setting represents the amount of time in milliseconds to wait
-         * for that session to close before timing out where the default value is 3000. Note that the server will
-         * eventually clean up dead sessions itself on expiration of the session or during shutdown.
-         *
-         * @deprecated As of release 3.3.11, replaced in essence by {@link #maxWaitForClose(int)} though behavior
-         * described here is still maintained.
-         */
-        @Deprecated
-        public Builder maxWaitForSessionClose(final int maxWait) {
-            this.maxWaitForSessionClose = maxWait;
-            return this;
-        }
-
-        /**
          * The amount of time in milliseconds to wait the connection to close before timing out where the default
          * value is 3000. This timeout allows for a delay to occur in waiting for remaining messages that may still
          * be returning from the server while a {@link Client#close()} is called.
-         * <p/>
-         * This setting is related to {@link #maxWaitForSessionClose} to some degree. This setting refers to a wait
-         * for standard requests (i.e. queries) but the {@link #maxWaitForSessionClose} refers to a wait for the
-         * "session close" message that occurs after all standard requests have returned (or timed out). There is
-         * generally no need to set {@link #maxWaitForSessionClose} if the server is on 3.3.11 or later as the close
-         * of the connection will trigger the close of the session and the release of resources.
          */
         public Builder maxWaitForClose(final int maxWait) {
             this.maxWaitForClose = maxWait;
@@ -1094,7 +998,7 @@
 
         public Cluster create() {
             if (addresses.size() == 0) addContactPoint("localhost");
-            if (null == serializer) serializer = Serializers.GRYO_V3D0.simpleInstance();
+            if (null == serializer) serializer = Serializers.GRAPHBINARY_V1D0.simpleInstance();
             return new Cluster(this);
         }
     }
@@ -1125,7 +1029,7 @@
         private boolean initialized;
         private final List<InetSocketAddress> contactPoints;
         private final Factory factory;
-        private final MessageSerializer serializer;
+        private final MessageSerializer<?> serializer;
         private final Settings.ConnectionPoolSettings connectionPoolSettings;
         private final LoadBalancingStrategy loadBalancingStrategy;
         private final AuthProperties authProps;
@@ -1161,16 +1065,11 @@
             connectionPoolSettings.maxSize = builder.maxConnectionPoolSize;
             connectionPoolSettings.minSize = builder.minConnectionPoolSize;
             connectionPoolSettings.maxWaitForConnection = builder.maxWaitForConnection;
-            connectionPoolSettings.maxWaitForSessionClose = builder.maxWaitForSessionClose;
             connectionPoolSettings.maxWaitForClose = builder.maxWaitForClose;
             connectionPoolSettings.maxContentLength = builder.maxContentLength;
             connectionPoolSettings.reconnectInterval = builder.reconnectInterval;
             connectionPoolSettings.resultIterationBatchSize = builder.resultIterationBatchSize;
             connectionPoolSettings.enableSsl = builder.enableSsl;
-            connectionPoolSettings.trustCertChainFile = builder.trustCertChainFile;
-            connectionPoolSettings.keyCertChainFile = builder.keyCertChainFile;
-            connectionPoolSettings.keyFile = builder.keyFile;
-            connectionPoolSettings.keyPassword = builder.keyPassword;
             connectionPoolSettings.keyStore = builder.keyStore;
             connectionPoolSettings.keyStorePassword = builder.keyStorePassword;
             connectionPoolSettings.trustStore = builder.trustStore;
@@ -1240,9 +1139,6 @@
             if (builder.maxWaitForConnection < 1)
                 throw new IllegalArgumentException("maxWaitForConnection must be greater than zero");
 
-            if (builder.maxWaitForSessionClose < 1)
-                throw new IllegalArgumentException("maxWaitForSessionClose must be greater than zero");
-
             if (builder.maxWaitForClose < 1)
                 throw new IllegalArgumentException("maxWaitForClose must be greater than zero");
 
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Connection.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Connection.java
index 8ffbd9e..b25045f 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Connection.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Connection.java
@@ -24,7 +24,6 @@
 import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
 import io.netty.bootstrap.Bootstrap;
 import io.netty.channel.Channel;
-import io.netty.channel.ChannelFuture;
 import io.netty.channel.ChannelFutureListener;
 import io.netty.channel.ChannelPromise;
 import io.netty.channel.socket.nio.NioSocketChannel;
@@ -38,7 +37,6 @@
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
@@ -57,12 +55,10 @@
     private final Cluster cluster;
     private final Client client;
     private final ConnectionPool pool;
-    private final long keepAliveInterval;
 
     public static final int MAX_IN_PROCESS = 4;
     public static final int MIN_IN_PROCESS = 1;
     public static final int MAX_WAIT_FOR_CONNECTION = 16000;
-    public static final int MAX_WAIT_FOR_SESSION_CLOSE = 3000;
     public static final int MAX_WAIT_FOR_CLOSE = 3000;
     public static final int MAX_CONTENT_LENGTH = 65536;
 
@@ -91,7 +87,6 @@
 
     private final AtomicReference<CompletableFuture<Void>> closeFuture = new AtomicReference<>();
     private final AtomicBoolean shutdownInitiated = new AtomicBoolean(false);
-    private final AtomicReference<ScheduledFuture> keepAliveFuture = new AtomicReference<>();
 
     public Connection(final URI uri, final ConnectionPool pool, final int maxInProcess) throws ConnectionException {
         this.uri = uri;
@@ -99,7 +94,6 @@
         this.client = pool.getClient();
         this.pool = pool;
         this.maxInProcess = maxInProcess;
-        this.keepAliveInterval = pool.settings().keepAliveInterval;
 
         connectionLabel = "Connection{host=" + pool.host + "}";
 
@@ -125,26 +119,17 @@
              * this closed connection.
              */
             final Connection thisConnection = this;
-            channel.closeFuture().addListener(new ChannelFutureListener() {
-                @Override
-                public void operationComplete(ChannelFuture future) throws Exception {
-                    logger.debug("OnChannelClose callback called for channel {}", channel);
+            channel.closeFuture().addListener((ChannelFutureListener) future -> {
+                logger.debug("OnChannelClose callback called for channel {}", channel);
 
-                    // Replace the channel if it was not intentionally closed using CloseAsync method.
-                    if (thisConnection.closeFuture.get() == null) {
-                        // delegate the task to worker thread and free up the event loop
-                        thisConnection.cluster.executor().submit(() -> thisConnection.pool.definitelyDestroyConnection(thisConnection));
-                    }
+                // Replace the channel if it was not intentionally closed using CloseAsync method.
+                if (thisConnection.closeFuture.get() == null) {
+                    // delegate the task to worker thread and free up the event loop
+                    thisConnection.cluster.executor().submit(() -> thisConnection.pool.definitelyDestroyConnection(thisConnection));
                 }
             });
 
             logger.info("Created new connection for {}", uri);
-
-            // Default WebSocketChannelizer uses Netty's IdleStateHandler
-            if (!(channelizer instanceof Channelizer.WebSocketChannelizer)) {
-                logger.debug("Using custom keep alive handler.");
-                scheduleKeepAlive();
-            }
         } catch (Exception ex) {
             throw new ConnectionException(uri, "Could not open " + this.toString(), ex);
         }
@@ -196,10 +181,6 @@
         final CompletableFuture<Void> future = new CompletableFuture<>();
         closeFuture.set(future);
 
-        // stop any pings being sent at the server for keep-alive
-        final ScheduledFuture keepAlive = keepAliveFuture.get();
-        if (keepAlive != null) keepAlive.cancel(true);
-
         // make sure all requests in the queue are fully processed before killing.  if they are then shutdown
         // can be immediate.  if not this method will signal the readCompleted future defined in the write()
         // operation to check if it can close.  in this way the connection no longer receives writes, but
@@ -274,42 +255,9 @@
                 });
         channel.writeAndFlush(requestMessage, requestPromise);
 
-        // Default WebSocketChannelizer uses Netty's IdleStateHandler
-        if (!(channelizer instanceof Channelizer.WebSocketChannelizer)) {
-            logger.debug("Using custom keep alive handler.");
-            scheduleKeepAlive();
-        }
-
         return requestPromise;
     }
 
-    /**
-     * @deprecated As of release 3.5.0, not directly replaced. The keep-alive functionality is delegated to Netty
-     * {@link io.netty.handler.timeout.IdleStateHandler} which is added to the pipeline in {@link Channelizer}.
-     */
-    private void scheduleKeepAlive() {
-        final Connection thisConnection = this;
-        // try to keep the connection alive if the channel allows such things - websockets will
-        if (channelizer.supportsKeepAlive() && keepAliveInterval > 0) {
-
-            final ScheduledFuture oldKeepAliveFuture = keepAliveFuture.getAndSet(cluster.scheduler().scheduleAtFixedRate(() -> {
-                logger.debug("Request sent to server to keep {} alive", thisConnection);
-                try {
-                    channel.writeAndFlush(channelizer.createKeepAliveMessage());
-                } catch (Exception ex) {
-                    // will just log this for now - a future real request can be responsible for the failure that
-                    // marks the host as dead. this also may not mean the host is actually dead. more robust handling
-                    // is in play for real requests, not this simple ping
-                    logger.warn(String.format("Keep-alive did not succeed on %s", thisConnection), ex);
-                }
-            }, keepAliveInterval, keepAliveInterval, TimeUnit.MILLISECONDS));
-
-            // try to cancel the old future if it's still un-executed - no need to ping since a new write has come
-            // through on the connection
-            if (oldKeepAliveFuture != null) oldKeepAliveFuture.cancel(true);
-        }
-    }
-
     private void returnToPool() {
         try {
             if (pool != null) pool.returnConnection(this);
@@ -351,40 +299,6 @@
         // the code in here is behind shutdownInitiated the synchronized doesn't seem necessary
         if (shutdownInitiated.compareAndSet(false, true)) {
             final String connectionInfo = this.getConnectionInfo();
-            // this block of code that "closes" the session is deprecated as of 3.3.11 - this message is going to be
-            // removed at 3.5.0. we will instead bind session closing to the close of the channel itself and not have
-            // this secondary operation here which really only acts as a means for clearing resources in a functioning
-            // session. "functioning" in this context means that the session is not locked up with a long running
-            // operation which will delay this close execution which ideally should be more immediate, as in the user
-            // is annoyed that a long run operation is happening and they want an immediate cancellation. that's the
-            // most likely use case. we also get the nice benefit that this if/then code just goes away as the
-            // Connection really shouldn't care about the specific Client implementation.
-            if (client instanceof Client.SessionedClient && !isDead()) {
-                final boolean forceClose = client.getSettings().getSession().get().isForceClosed();
-                final RequestMessage closeMessage = client.buildMessage(
-                        RequestMessage.build(Tokens.OPS_CLOSE).addArg(Tokens.ARGS_FORCE, forceClose)).create();
-
-                final CompletableFuture<ResultSet> closed = new CompletableFuture<>();
-                write(closeMessage, closed);
-
-                try {
-                    // make sure we get a response here to validate that things closed as expected.  on error, we'll let
-                    // the server try to clean up on its own.  the primary error here should probably be related to
-                    // protocol issues which should not be something a user has to fuss with.
-                    closed.join().all().get(cluster.getMaxWaitForSessionClose(), TimeUnit.MILLISECONDS);
-                } catch (TimeoutException ex) {
-                    final String msg = String.format(
-                            "Timeout while trying to close connection on %s - force closing - server will close session on shutdown or expiration.",
-                            ((Client.SessionedClient) client).getSessionId());
-                    logger.warn(msg, ex);
-                } catch (Exception ex) {
-                    final String msg = String.format(
-                            "Encountered an error trying to close connection on %s - force closing - server will close session on shutdown or expiration.",
-                            ((Client.SessionedClient) client).getSessionId());
-                    logger.warn(msg, ex);
-                }
-            }
-
             channelizer.close(channel);
 
             final ChannelPromise promise = channel.newPromise();
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Handler.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Handler.java
index 3189d08..11bf8b4 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Handler.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Handler.java
@@ -222,31 +222,16 @@
             final ResultQueue queue = pending.get(response.getRequestId());
             if (statusCode == ResponseStatusCode.SUCCESS || statusCode == ResponseStatusCode.PARTIAL_CONTENT) {
                 final Object data = response.getResult().getData();
-                final Map<String,Object> meta = response.getResult().getMeta();
 
-                if (!meta.containsKey(Tokens.ARGS_SIDE_EFFECT_KEY)) {
-                    // this is a "result" from the server which is either the result of a script or a
-                    // serialized traversal
-                    if (data instanceof List) {
-                        // unrolls the collection into individual results to be handled by the queue.
-                        final List<Object> listToUnroll = (List<Object>) data;
-                        listToUnroll.forEach(item -> queue.add(new Result(item)));
-                    } else {
-                        // since this is not a list it can just be added to the queue
-                        queue.add(new Result(response.getResult().getData()));
-                    }
+                // this is a "result" from the server which is either the result of a script or a
+                // serialized traversal
+                if (data instanceof List) {
+                    // unrolls the collection into individual results to be handled by the queue.
+                    final List<Object> listToUnroll = (List<Object>) data;
+                    listToUnroll.forEach(item -> queue.add(new Result(item)));
                 } else {
-                    // this is the side-effect from the server which is generated from a serialized traversal
-                    final String aggregateTo = meta.getOrDefault(Tokens.ARGS_AGGREGATE_TO, Tokens.VAL_AGGREGATE_TO_NONE).toString();
-                    if (data instanceof List) {
-                        // unrolls the collection into individual results to be handled by the queue.
-                        final List<Object> listOfSideEffects = (List<Object>) data;
-                        listOfSideEffects.forEach(sideEffect -> queue.addSideEffect(aggregateTo, sideEffect));
-                    } else {
-                        // since this is not a list it can just be added to the queue. this likely shouldn't occur
-                        // however as the protocol will typically push everything to list first.
-                        queue.addSideEffect(aggregateTo, data);
-                    }
+                    // since this is not a list it can just be added to the queue
+                    queue.add(new Result(response.getResult().getData()));
                 }
             } else {
                 // this is a "success" but represents no results otherwise it is an error
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/MessageSerializer.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/MessageSerializer.java
index af39cd4..8b21ec4 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/MessageSerializer.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/MessageSerializer.java
@@ -42,11 +42,16 @@
  *
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
-public interface MessageSerializer {
+public interface MessageSerializer<M> {
 
     static final Logger logger = LoggerFactory.getLogger(MessageSerializer.class);
 
     /**
+     * Gets the "mapper" that performs the underlying serialization work.
+     */
+    M getMapper();
+
+    /**
      * Serialize a {@link ResponseMessage} to a Netty {@code ByteBuf}.
      *
      * @param responseMessage The response message to serialize to bytes.
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/RequestOptions.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/RequestOptions.java
index 06bce18..dcc7cdf 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/RequestOptions.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/RequestOptions.java
@@ -85,6 +85,7 @@
         private Long timeout = null;
         private UUID overrideRequestId = null;
         private String userAgent = null;
+        private boolean maintainStateAfterException = false;
 
         /**
          * The aliases to set on the request.
@@ -127,7 +128,7 @@
         }
 
         /**
-         * The per client request override in milliseconds for the server configured {@code scriptEvaluationTimeout}.
+         * The per client request override in milliseconds for the server configured {@code evaluationTimeout}.
          * If this value is not set, then the configuration for the server is used.
          */
         public Builder timeout(final long timeout) {
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ResultQueue.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ResultQueue.java
index 29a6453..8ce4fba 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ResultQueue.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ResultQueue.java
@@ -18,21 +18,15 @@
  */
 package org.apache.tinkerpop.gremlin.driver;
 
-import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
-import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.BulkSet;
 import org.javatuples.Pair;
 
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Queue;
-import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.LinkedBlockingQueue;
@@ -74,65 +68,6 @@
         tryDrainNextWaiting(false);
     }
 
-    /**
-     * Adds a side-effect to the queue which may later be read by the {@link ResultSet}. Note that the side-effect
-     * is only returned when a {@link Traversal} is submitted and refers to the side-effects defined in that traversal.
-     * A "script" will not return side-effects.
-     *
-     * @param aggregateTo the value of the {@link ResponseMessage} metadata for {@link Tokens#ARGS_AGGREGATE_TO}.
-     * @param sideEffectValue the value of the side-effect itself
-     * @deprecated As of release 3.3.8, not directly replaced in the protocol as side-effect retrieval after
-     * traversal iteration is not being promoted anymore as a feature.
-     */
-    @Deprecated
-    public void addSideEffect(final String aggregateTo, final Object sideEffectValue) {
-        switch (aggregateTo) {
-            case Tokens.VAL_AGGREGATE_TO_BULKSET:
-                if (!(sideEffectValue instanceof Traverser.Admin))
-                    throw new IllegalStateException(String.format("Side-effect value %s is a %s which does not aggregate to %s",
-                            sideEffectValue, sideEffectValue.getClass().getSimpleName(), aggregateTo));
-
-                if (null == aggregatedResult) aggregatedResult = new BulkSet();
-
-                final BulkSet<Object> bs = validate(aggregateTo, BulkSet.class);
-                final Traverser.Admin traverser = (Traverser.Admin) sideEffectValue;
-                bs.add(traverser.get(), traverser.bulk());
-                break;
-            case Tokens.VAL_AGGREGATE_TO_LIST:
-                if (null == aggregatedResult) aggregatedResult = new ArrayList();
-                final List<Object> list = validate(aggregateTo, List.class);
-                list.add(sideEffectValue);
-                break;
-            case Tokens.VAL_AGGREGATE_TO_SET:
-                if (null == aggregatedResult) aggregatedResult = new HashSet();
-                final Set<Object> set = validate(aggregateTo, Set.class);
-                set.add(sideEffectValue);
-                break;
-            case Tokens.VAL_AGGREGATE_TO_MAP:
-                if (!(sideEffectValue instanceof Map.Entry) && !(sideEffectValue instanceof Map))
-                    throw new IllegalStateException(String.format("Side-effect value %s is a %s which does not aggregate to %s",
-                            sideEffectValue, sideEffectValue.getClass().getSimpleName(), aggregateTo));
-
-                // some serialization formats (e.g. graphson) may deserialize a Map.Entry to a Map with a single entry
-                if (sideEffectValue instanceof Map && ((Map) sideEffectValue).size() != 1)
-                    throw new IllegalStateException(String.format("Side-effect value %s is a %s which does not aggregate to %s as it is a Map that does not have one entry",
-                            sideEffectValue, sideEffectValue.getClass().getSimpleName(), aggregateTo));
-
-                if (null == aggregatedResult) aggregatedResult =  new HashMap();
-
-                final Map<Object,Object > m = validate(aggregateTo, Map.class);
-                final Map.Entry entry = sideEffectValue instanceof Map.Entry ?
-                        (Map.Entry) sideEffectValue : (Map.Entry) ((Map) sideEffectValue).entrySet().iterator().next();
-                m.put(entry.getKey(), entry.getValue());
-                break;
-            case Tokens.VAL_AGGREGATE_TO_NONE:
-                if (null == aggregatedResult) aggregatedResult = sideEffectValue;
-                break;
-            default:
-                throw new IllegalStateException(String.format("%s is an invalid value for %s", aggregateTo, Tokens.ARGS_AGGREGATE_TO));
-        }
-    }
-
     private <V> V validate(final String aggregateTo, final Class<?> expected) {
         if (!(expected.isAssignableFrom(aggregatedResult.getClass())))
             throw new IllegalStateException(String.format("Side-effect \"%s\" contains the type %s that is not acceptable for %s",
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Settings.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Settings.java
index f1f2fe6..0e8ae0f 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Settings.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Settings.java
@@ -18,8 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.driver;
 
-import org.apache.commons.configuration.Configuration;
-import org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0;
+import org.apache.commons.configuration2.Configuration;
+import org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1;
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 import org.yaml.snakeyaml.TypeDescription;
 import org.yaml.snakeyaml.Yaml;
@@ -156,9 +156,7 @@
             final Configuration serializerConfigConf = conf.subset("serializer.config");
             if (IteratorUtils.count(serializerConfigConf.getKeys()) > 0) {
                 final Map<String,Object> m = new HashMap<>();
-                serializerConfigConf.getKeys().forEachRemaining(name -> {
-                    m.put(name, serializerConfigConf.getProperty(name));
-                });
+                serializerConfigConf.getKeys().forEachRemaining(name -> m.put(name, serializerConfigConf.getProperty(name)));
                 serializerSettings.config = m;
             }
             settings.serializer = serializerSettings;
@@ -174,18 +172,6 @@
             if (connectionPoolConf.containsKey("enableSsl"))
                 cpSettings.enableSsl = connectionPoolConf.getBoolean("enableSsl");
 
-            if (connectionPoolConf.containsKey("keyCertChainFile"))
-                cpSettings.keyCertChainFile = connectionPoolConf.getString("keyCertChainFile");
-
-            if (connectionPoolConf.containsKey("keyFile"))
-                cpSettings.keyFile = connectionPoolConf.getString("keyFile");
-
-            if (connectionPoolConf.containsKey("keyPassword"))
-                cpSettings.keyPassword = connectionPoolConf.getString("keyPassword");
-
-            if (connectionPoolConf.containsKey("trustCertChainFile"))
-                cpSettings.trustCertChainFile = connectionPoolConf.getString("trustCertChainFile");
-
             if (connectionPoolConf.containsKey("keyStore"))
                 cpSettings.keyStore = connectionPoolConf.getString("keyStore");
 
@@ -236,9 +222,6 @@
             if (connectionPoolConf.containsKey("maxWaitForConnection"))
                 cpSettings.maxWaitForConnection = connectionPoolConf.getInt("maxWaitForConnection");
 
-            if (connectionPoolConf.containsKey("maxWaitForSessionClose"))
-                cpSettings.maxWaitForSessionClose = connectionPoolConf.getInt("maxWaitForSessionClose");
-
             if (connectionPoolConf.containsKey("maxWaitForClose"))
                 cpSettings.maxWaitForClose = connectionPoolConf.getInt("maxWaitForClose");
 
@@ -273,34 +256,6 @@
         public boolean enableSsl = false;
 
         /**
-         * The trusted certificate in PEM format.
-         * @deprecated As of release 3.2.10, replaced by {@link #trustStore}
-         */
-        @Deprecated
-        public String trustCertChainFile = null;
-
-        /**
-         * The X.509 certificate chain file in PEM format.
-         * @deprecated As of release 3.2.10, replaced by {@link #keyStore}
-         */
-        @Deprecated
-        public String keyCertChainFile = null;
-
-        /**
-         * The PKCS#8 private key file in PEM format.
-         * @deprecated As of release 3.2.10, replaced by {@link #keyStore}
-         */
-        @Deprecated
-        public String keyFile = null;
-
-        /**
-         * The password of the {@link #keyFile}, or {@code null} if it's not password-protected.
-         * @deprecated As of release 3.2.10, replaced by {@link #keyStorePassword}
-         */
-        @Deprecated
-        public String keyPassword = null;
-
-        /**
          * JSSE keystore file path. Similar to setting JSSE property
          * {@code javax.net.ssl.keyStore}.
          */
@@ -366,9 +321,8 @@
         public int maxSize = ConnectionPool.MAX_POOL_SIZE;
 
         /**
-         * Length of time in milliseconds to wait on an idle connection before sending a keep-alive request. This
-         * setting is only relevant to {@link Channelizer} implementations that return {@code true} for
-         * {@link Channelizer#supportsKeepAlive()}. Set to zero to disable this feature.
+         * Length of time in milliseconds to wait on an idle connection before sending a keep-alive request. Set to
+         * zero to disable this feature.
          */
         public long keepAliveInterval = Connection.KEEP_ALIVE_INTERVAL;
 
@@ -404,16 +358,6 @@
         public int maxWaitForConnection = Connection.MAX_WAIT_FOR_CONNECTION;
 
         /**
-         * If the connection is using a "session" this setting represents the amount of time in milliseconds to wait
-         * for that session to close before timing out where the default value is 3000. Note that the server will
-         * eventually clean up dead sessions itself on expiration of the session or during shutdown.
-         *
-         * @deprecated As of release 3.3.11, replaced in essence by {@link #maxWaitForClose}.
-         */
-        @Deprecated
-        public int maxWaitForSessionClose = Connection.MAX_WAIT_FOR_SESSION_CLOSE;
-
-        /**
          * The amount of time in milliseconds to wait the connection to close before timing out where the default
          * value is 3000. This timeout allows for a delay to occur in waiting for remaining messages that may still
          * be returning from the server while a {@link Client#close()} is called.
@@ -466,17 +410,18 @@
         /**
          * The fully qualified class name of the {@link MessageSerializer} that will be used to communicate with the
          * server. Note that the serializer configured on the client should be supported by the server configuration.
+         * By default the setting is configured to {@link GraphBinaryMessageSerializerV1}.
          */
-        public String className = GryoMessageSerializerV3d0.class.getCanonicalName();
+        public String className = GraphBinaryMessageSerializerV1.class.getCanonicalName();
 
         /**
          * The configuration for the specified serializer with the {@link #className}.
          */
         public Map<String, Object> config = null;
 
-        public MessageSerializer create() throws Exception {
-            final Class clazz = Class.forName(className);
-            final MessageSerializer serializer = (MessageSerializer) clazz.newInstance();
+        public MessageSerializer<?> create() throws Exception {
+            final Class<?> clazz = Class.forName(className);
+            final MessageSerializer<?> serializer = (MessageSerializer<?>) clazz.newInstance();
             Optional.ofNullable(config).ifPresent(c -> serializer.configure(c, null));
             return serializer;
         }
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Tokens.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Tokens.java
index 92641a7..c5936a2 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Tokens.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Tokens.java
@@ -37,20 +37,6 @@
     public static final String OPS_CLOSE = "close";
 
     /**
-     * @deprecated As of release 3.3.8, not directly replaced in the protocol as side-effect retrieval after
-     * traversal iteration is not being promoted anymore as a feature.
-     */
-    @Deprecated
-    public static final String OPS_GATHER = "gather";
-
-    /**
-     * @deprecated As of release 3.3.8, not directly replaced in the protocol as side-effect retrieval after
-     * traversal iteration is not being promoted anymore as a feature.
-     */
-    @Deprecated
-    public static final String OPS_KEYS = "keys";
-
-    /**
      * The key for the unique identifier of the request.
      */
     public static final String REQUEST_ID = "requestId";
@@ -85,12 +71,6 @@
     public static final String ARGS_LANGUAGE = "language";
 
     /**
-     * @deprecated As of release 3.3.9, replaced by {@link #ARGS_EVAL_TIMEOUT}.
-     */
-    @Deprecated
-    public static final String ARGS_SCRIPT_EVAL_TIMEOUT = "scriptEvaluationTimeout";
-
-    /**
      * Argument name that allows the override of the server setting that determines the maximum time to wait for a
      * request to execute on the server.
      */
@@ -98,71 +78,22 @@
     public static final String ARGS_HOST = "host";
     public static final String ARGS_SESSION = "session";
     public static final String ARGS_MANAGE_TRANSACTION = "manageTransaction";
+
+    /**
+     * Argument name that is intended to be used with a session which when its value is {@code true} makes it so
+     * that a processing error or request timeout will not close the session, but leave it to continue processing in
+     * whatever state it may hold. This argument only applies to the {@code UnifiedChannelizer}.
+     */
+    public static final String ARGS_MAINTAIN_STATE_AFTER_EXCEPTION = "maintainStateAfterException";
     public static final String ARGS_SASL = "sasl";
     public static final String ARGS_SASL_MECHANISM = "saslMechanism";
 
     /**
-     * @deprecated As of release 3.3.8, not directly replaced in the protocol as side-effect retrieval after
-     * traversal iteration is not being promoted anymore as a feature.
-     */
-    @Deprecated
-    public static final String ARGS_SIDE_EFFECT = "sideEffect";
-
-    /**
-     * @deprecated As of release 3.3.8, not directly replaced in the protocol as side-effect retrieval after
-     * traversal iteration is not being promoted anymore as a feature.
-     */
-    @Deprecated
-    public static final String ARGS_AGGREGATE_TO = "aggregateTo";
-
-    /**
-     * @deprecated As of release 3.3.8, not directly replaced in the protocol as side-effect retrieval after
-     * traversal iteration is not being promoted anymore as a feature.
-     */
-    @Deprecated
-    public static final String ARGS_SIDE_EFFECT_KEY = "sideEffectKey";
-
-    /**
      * A value that is a custom string that the user can pass to a server that might accept it for purpose of
      * identifying the kind of client it came from.
      */
     public static final String ARGS_USER_AGENT = "userAgent";
 
-    /**
-     * @deprecated As of release 3.3.8, not directly replaced in the protocol as side-effect retrieval after
-     * traversal iteration is not being promoted anymore as a feature.
-     */
-    @Deprecated
-    public static final String VAL_AGGREGATE_TO_BULKSET = "bulkset";
-
-    /**
-     * @deprecated As of release 3.3.8, not directly replaced in the protocol as side-effect retrieval after
-     * traversal iteration is not being promoted anymore as a feature.
-     */
-    @Deprecated
-    public static final String VAL_AGGREGATE_TO_LIST = "list";
-
-    /**
-     * @deprecated As of release 3.3.8, not directly replaced in the protocol as side-effect retrieval after
-     * traversal iteration is not being promoted anymore as a feature.
-     */
-    @Deprecated
-    public static final String VAL_AGGREGATE_TO_MAP = "map";
-
-    /**
-     * @deprecated As of release 3.3.8, not directly replaced in the protocol as side-effect retrieval after
-     * traversal iteration is not being promoted anymore as a feature.
-     */
-    @Deprecated
-    public static final String VAL_AGGREGATE_TO_NONE = "none";
-
-    /**
-     * @deprecated As of release 3.3.8, not directly replaced in the protocol as side-effect retrieval after
-     * traversal iteration is not being promoted anymore as a feature.
-     */
-    @Deprecated
-    public static final String VAL_AGGREGATE_TO_SET = "set";
-
     public static final String VAL_TRAVERSAL_SOURCE_ALIAS = "g";
 
     public static final String STATUS_ATTRIBUTE_EXCEPTIONS = "exceptions";
@@ -173,11 +104,11 @@
      * Implementations that set this key should consider using one of
      * these two recommended value types:
      * <ul>
-     *     <li>A {@link java.util.List} implementation containing
-     *     references for which {@link String#valueOf(Object)} produces
+     *     <li>A {@code List} implementation containing
+     *     references for which {@code String#valueOf(Object)} produces
      *     a meaningful return value.  For example, a list of strings.</li>
      *     <li>Otherwise, any single non-list object for which
-     *     {@link String#valueOf(Object)} produces a meaningful return value.
+     *     {@code String#valueOf(Object)} produces a meaningful return value.
      *     For example, a string.</li>
      * </ul>
      */
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/NioGremlinRequestEncoder.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/NioGremlinRequestEncoder.java
deleted file mode 100644
index 1330a7e..0000000
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/NioGremlinRequestEncoder.java
+++ /dev/null
@@ -1,75 +0,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.
- */
-package org.apache.tinkerpop.gremlin.driver.handler;
-
-import org.apache.tinkerpop.gremlin.driver.MessageSerializer;
-import org.apache.tinkerpop.gremlin.driver.exception.ResponseException;
-import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
-import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
-import org.apache.tinkerpop.gremlin.driver.ser.MessageTextSerializer;
-import io.netty.buffer.ByteBuf;
-import io.netty.channel.ChannelHandler;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.handler.codec.MessageToByteEncoder;
-import io.netty.util.CharsetUtil;
-import org.apache.tinkerpop.gremlin.driver.simple.WebSocketClient;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * @author Stephen Mallette (http://stephen.genoprime.com)
- * @deprecated As of release 3.3.10, not replaced, use {@link WebSocketClient}.
- */
-@Deprecated
-public final class NioGremlinRequestEncoder extends MessageToByteEncoder<Object> {
-    private boolean binaryEncoding = false;
-
-    private final MessageSerializer serializer;
-
-    public NioGremlinRequestEncoder(final boolean binaryEncoding, final MessageSerializer serializer) {
-        this.binaryEncoding = binaryEncoding;
-        this.serializer = serializer;
-    }
-
-    @Override
-    protected void encode(final ChannelHandlerContext channelHandlerContext, final Object msg, final ByteBuf byteBuf) throws Exception {
-        final RequestMessage requestMessage = (RequestMessage) msg;
-        try {
-            if (binaryEncoding) {
-                // wrap the serialized message/payload inside of a "frame".  this works around the problem where
-                // the length of the payload is not encoded into the general protocol.  that length isn't needed
-                // for websockets because under that protocol, the message is wrapped in a "websocket frame". this
-                // is not the optimal way to deal with this really, but it does prevent a protocol change in this
-                // immediate moment trying to get the NioChannelizer working.
-                final ByteBuf bytes = serializer.serializeRequestAsBinary(requestMessage, channelHandlerContext.alloc());
-                byteBuf.writeInt(bytes.capacity());
-                byteBuf.writeBytes(bytes);
-            } else {
-                final MessageTextSerializer textSerializer = (MessageTextSerializer) serializer;
-                final byte [] bytes = textSerializer.serializeRequestAsString(requestMessage).getBytes(CharsetUtil.UTF_8);
-                byteBuf.writeInt(bytes.length);
-                byteBuf.writeBytes(bytes);
-            }
-        } catch (Exception ex) {
-            throw new ResponseException(ResponseStatusCode.REQUEST_ERROR_SERIALIZATION, String.format(
-                    "An error occurred during serialization of this request [%s] - it could not be sent to the server - Reason: %s",
-                    requestMessage, ex));
-        }
-    }
-}
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/NioGremlinResponseDecoder.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/NioGremlinResponseDecoder.java
deleted file mode 100644
index 25e3a1c..0000000
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/NioGremlinResponseDecoder.java
+++ /dev/null
@@ -1,63 +0,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.
- */
-package org.apache.tinkerpop.gremlin.driver.handler;
-
-import io.netty.handler.codec.ReplayingDecoder;
-import org.apache.tinkerpop.gremlin.driver.MessageSerializer;
-import io.netty.buffer.ByteBuf;
-import io.netty.channel.ChannelHandlerContext;
-import org.apache.tinkerpop.gremlin.driver.simple.WebSocketClient;
-
-import java.util.List;
-
-/**
- * @author Stephen Mallette (http://stephen.genoprime.com)
- * @deprecated As of release 3.3.10, not replaced, use {@link WebSocketClient}.
- */
-@Deprecated
-public final class NioGremlinResponseDecoder extends ReplayingDecoder<NioGremlinResponseDecoder.DecoderState> {
-    private final MessageSerializer serializer;
-    private int messageLength;
-
-    public NioGremlinResponseDecoder(final MessageSerializer serializer) {
-        super(DecoderState.MESSAGE_LENGTH);
-        this.serializer = serializer;
-    }
-
-    @Override
-    protected void decode(final ChannelHandlerContext channelHandlerContext, final ByteBuf byteBuf, final List<Object> objects) throws Exception {
-        switch (state()) {
-            case MESSAGE_LENGTH:
-                messageLength = byteBuf.readInt();
-                checkpoint(DecoderState.MESSAGE);
-            case MESSAGE:
-                final ByteBuf messageFrame = byteBuf.readBytes(messageLength);
-                objects.add(serializer.deserializeResponse(messageFrame));
-                checkpoint(DecoderState.MESSAGE_LENGTH);
-                break;
-            default:
-                throw new Error("Invalid message received from Gremlin Server");
-        }
-    }
-
-    public enum DecoderState {
-        MESSAGE_LENGTH,
-        MESSAGE
-    }
-}
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/WebSocketGremlinRequestEncoder.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/WebSocketGremlinRequestEncoder.java
index 9ffbc60..92dedab 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/WebSocketGremlinRequestEncoder.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/WebSocketGremlinRequestEncoder.java
@@ -39,9 +39,9 @@
 public final class WebSocketGremlinRequestEncoder extends MessageToMessageEncoder<RequestMessage> {
     private final boolean binaryEncoding;
 
-    private final MessageSerializer serializer;
+    private final MessageSerializer<?> serializer;
 
-    public WebSocketGremlinRequestEncoder(final boolean binaryEncoding, final MessageSerializer serializer) {
+    public WebSocketGremlinRequestEncoder(final boolean binaryEncoding, final MessageSerializer<?> serializer) {
         this.binaryEncoding = binaryEncoding;
         this.serializer = serializer;
     }
@@ -53,7 +53,7 @@
                 final ByteBuf encodedMessage = serializer.serializeRequestAsBinary(requestMessage, channelHandlerContext.alloc());
                 objects.add(new BinaryWebSocketFrame(encodedMessage));
             } else {
-                final MessageTextSerializer textSerializer = (MessageTextSerializer) serializer;
+                final MessageTextSerializer<?> textSerializer = (MessageTextSerializer<?>) serializer;
                 objects.add(new TextWebSocketFrame(textSerializer.serializeRequestAsString(requestMessage)));
             }
         } catch (Exception ex) {
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/WebSocketGremlinResponseDecoder.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/WebSocketGremlinResponseDecoder.java
index 3b292f8..2e93061 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/WebSocketGremlinResponseDecoder.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/WebSocketGremlinResponseDecoder.java
@@ -34,9 +34,9 @@
  */
 @ChannelHandler.Sharable
 public final class WebSocketGremlinResponseDecoder extends MessageToMessageDecoder<WebSocketFrame> {
-    private final MessageSerializer serializer;
+    private final MessageSerializer<?> serializer;
 
-    public WebSocketGremlinResponseDecoder(final MessageSerializer serializer) {
+    public WebSocketGremlinResponseDecoder(final MessageSerializer<?> serializer) {
         this.serializer = serializer;
     }
 
@@ -47,7 +47,7 @@
             objects.add(serializer.deserializeResponse(tf.content()));
         } else if (webSocketFrame instanceof TextWebSocketFrame) {
             final TextWebSocketFrame tf = (TextWebSocketFrame) webSocketFrame;
-            final MessageTextSerializer textSerializer = (MessageTextSerializer) serializer;
+            final MessageTextSerializer<?> textSerializer = (MessageTextSerializer<?>) serializer;
             objects.add(textSerializer.deserializeResponse(tf.text()));
         } else {
             throw new RuntimeException(String.format("WebSocket channel does not handle this type of message: %s", webSocketFrame.getClass().getName()));
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/message/ResponseStatusCode.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/message/ResponseStatusCode.java
index c83493a..4f43f65 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/message/ResponseStatusCode.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/message/ResponseStatusCode.java
@@ -33,39 +33,59 @@
 public enum ResponseStatusCode {
     /**
      * The server successfully processed a request to completion - there are no messages remaining in this stream.
+     *
+     * @since 3.0.0-incubating
      */
     SUCCESS(200),
 
     /**
      * The server processed the request but there is no result to return (e.g. an {@link Iterator} with no elements).
+     *
+     * @since 3.0.0-incubating
      */
     NO_CONTENT(204),
 
     /**
      * The server successfully returned some content, but there is more in the stream to arrive - wait for a
      * {@link #SUCCESS} to signify the end of the stream.
+     *
+     * @since 3.0.0-incubating
      */
     PARTIAL_CONTENT(206),
 
     /**
      * The server could not authenticate the request or the client requested a resource it did not have access to.
+     *
+     * @since 3.0.0-incubating
      */
     UNAUTHORIZED(401),
 
     /**
      * The server could authenticate the request, but will not fulfill it.  This is a general purpose code that
-     * would typically be returned if the request is authenticated but not authorized to do what it is doing. This
-     * code is for future use.
+     * would typically be returned if the request is authenticated but not authorized to do what it is doing.
+     *
+     * @since 3.0.1-incubating
      */
     FORBIDDEN(403),
 
     /**
      * A challenge from the server for the client to authenticate its request.
+     *
+     * @since 3.0.1-incubating
      */
     AUTHENTICATE(407),
 
     /**
+     * Indicates that too many requests have been sent in a given amount of time.
+     *
+     * @since 3.5.0
+     */
+    TOO_MANY_REQUESTS(429),
+
+    /**
      * The request message contains objects that were not serializable on the client side.
+     *
+     * @since 3.3.6
      */
     REQUEST_ERROR_SERIALIZATION(497),
 
@@ -73,29 +93,49 @@
      * The request message was not properly formatted which means it could not be parsed at all or the "op" code was
      * not recognized such that Gremlin Server could properly route it for processing.  Check the message format and
      * retry the request.
+     *
+     * @since 3.0.0-incubating
      */
     REQUEST_ERROR_MALFORMED_REQUEST(498),
 
     /**
      * The request message was parseable, but the arguments supplied in the message were in conflict or incomplete.
      * Check the message format and retry the request.
+     *
+     * @since 3.0.0-incubating
      */
     REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS(499),
 
     /**
      * A general server error occurred that prevented the request from being processed.
+     *
+     * @since 3.0.0-incubating
      */
     SERVER_ERROR(500),
 
     /**
+     * A server error that indicates that the client should retry the request. A graph will typically return this error
+     * when a transaction fails due to a locking exception or some other sort of concurrent modification. In other
+     * words, the request was likely valid but the state of the server at the particular time the request arrived
+     * could not be processed to success, but could be at a later moment.
+     *
+     * @since 3.4.11
+     */
+    SERVER_ERROR_TEMPORARY(596),
+
+    /**
      * The request submitted for processing evaluated by the server with errors and could not be processed.
      * Check the script or remote traversal submitted for errors or other problems and then resubmit.
+     *
+     * @since 3.0.0-incubating
      */
-    SERVER_ERROR_SCRIPT_EVALUATION(597),
+    SERVER_ERROR_EVALUATION(597),
 
     /**
      * The server exceeded one of the timeout settings for the request and could therefore only partially responded
      * or did not respond at all.
+     *
+     * @since 3.0.0-incubating
      */
     SERVER_ERROR_TIMEOUT(598),
 
@@ -103,11 +143,13 @@
      * The server was not capable of serializing an object that was returned from the script supplied on the request.
      * Either transform the object into something Gremlin Server can process within the script or install mapper
      * serialization classes to Gremlin Server.
+     *
+     * @since 3.0.0-incubating
      */
     SERVER_ERROR_SERIALIZATION(599);
 
     private final int value;
-    private static Map<Integer, ResponseStatusCode> codeValueMap = new HashMap<>();
+    private final static Map<Integer, ResponseStatusCode> codeValueMap = new HashMap<>();
 
     static {
         Stream.of(ResponseStatusCode.values()).forEach(code -> codeValueMap.put(code.getValue(), code));
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteConnection.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteConnection.java
index 8898e87..ac4eed6 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteConnection.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteConnection.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.driver.remote;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.driver.Client;
 import org.apache.tinkerpop.gremlin.driver.Cluster;
 import org.apache.tinkerpop.gremlin.driver.RequestOptions;
@@ -29,6 +29,7 @@
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.OptionsStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.util.BytecodeHelper;
+import org.apache.tinkerpop.gremlin.structure.Transaction;
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 
 import java.util.Iterator;
@@ -38,7 +39,6 @@
 import java.util.concurrent.CompletableFuture;
 
 import static org.apache.tinkerpop.gremlin.driver.Tokens.ARGS_BATCH_SIZE;
-import static org.apache.tinkerpop.gremlin.driver.Tokens.ARGS_SCRIPT_EVAL_TIMEOUT;
 import static org.apache.tinkerpop.gremlin.driver.Tokens.ARGS_EVAL_TIMEOUT;
 import static org.apache.tinkerpop.gremlin.driver.Tokens.ARGS_USER_AGENT;
 import static org.apache.tinkerpop.gremlin.driver.Tokens.REQUEST_ID;
@@ -56,7 +56,7 @@
 
     private static final String DEFAULT_TRAVERSAL_SOURCE = "g";
 
-    private final Client client;
+    final Client client;
     private final boolean tryCloseCluster;
     private final boolean tryCloseClient;
     private final String remoteTraversalSourceName;
@@ -114,11 +114,15 @@
     }
 
     private DriverRemoteConnection(final Client client, final String remoteTraversalSourceName) {
+        this(client, remoteTraversalSourceName, false);
+    }
+
+    private DriverRemoteConnection(final Client client, final String remoteTraversalSourceName, final boolean tryCloseClient) {
         this.client = client.alias(remoteTraversalSourceName);
         this.remoteTraversalSourceName = remoteTraversalSourceName;
         this.tryCloseCluster = false;
-        attachElements = false;
-        tryCloseClient = false;
+        this.attachElements = false;
+        this.tryCloseClient = tryCloseClient;
     }
 
     /**
@@ -228,6 +232,18 @@
         }
     }
 
+    /**
+     * If the connection is bound to a session, then get the session identifier from it.
+     */
+    Optional<String> getSessionId() {
+        if (client instanceof Client.SessionedClient) {
+            Client.SessionedClient c = (Client.SessionedClient) client;
+            return Optional.of(c.getSessionId());
+        }
+
+        return Optional.empty();
+    }
+
     protected static RequestOptions getRequestOptions(final Bytecode bytecode) {
         final Iterator<OptionsStrategy> itty = BytecodeHelper.findStrategies(bytecode, OptionsStrategy.class);
         final RequestOptions.Builder builder = RequestOptions.build();
@@ -236,8 +252,6 @@
             final Map<String,Object> options = optionsStrategy.getOptions();
             if (options.containsKey(ARGS_EVAL_TIMEOUT))
                 builder.timeout((long) options.get(ARGS_EVAL_TIMEOUT));
-            if (options.containsKey(ARGS_SCRIPT_EVAL_TIMEOUT))
-                builder.timeout((long) options.get(ARGS_SCRIPT_EVAL_TIMEOUT));
             if (options.containsKey(REQUEST_ID))
                 builder.overrideRequestId((UUID) options.get(REQUEST_ID));
             if (options.containsKey(ARGS_BATCH_SIZE))
@@ -261,6 +275,16 @@
         }
     }
 
+    /**
+     * Constructs a new {@link DriverRemoteTransaction}.
+     */
+    @Override
+    public Transaction tx() {
+        final DriverRemoteConnection session = new DriverRemoteConnection(
+                client.getCluster().connect(UUID.randomUUID().toString()), remoteTraversalSourceName, true);
+        return new DriverRemoteTransaction(session);
+    }
+
     @Override
     public String toString() {
         return "DriverServerConnection-" + client.getCluster() + " [graph=" + remoteTraversalSourceName + "]";
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTransaction.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTransaction.java
new file mode 100644
index 0000000..bc11583
--- /dev/null
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTransaction.java
@@ -0,0 +1,174 @@
+/*
+ * 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.driver.remote;
+
+import org.apache.tinkerpop.gremlin.process.remote.RemoteConnection;
+import org.apache.tinkerpop.gremlin.process.remote.RemoteConnectionException;
+import org.apache.tinkerpop.gremlin.process.remote.traversal.RemoteTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
+import org.apache.tinkerpop.gremlin.process.traversal.GraphOp;
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
+import org.apache.tinkerpop.gremlin.structure.Transaction;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+
+import static org.apache.tinkerpop.gremlin.process.traversal.GraphOp.TX_COMMIT;
+import static org.apache.tinkerpop.gremlin.process.traversal.GraphOp.TX_ROLLBACK;
+
+/**
+ * A remote {@link Transaction} implementation that is implemented with the Java driver. It is also a proxy for a
+ * {@link RemoteConnection} that is bound to a session.
+ * <p/>
+ * For users, starting a transaction with {@link #begin()} will produce a {@link TraversalSource} that can be used
+ * across multiple threads sending the bytecode based requests to a remote session. It is worth noting that the session
+ * will process these requests in a serial fashion and not in parallel. Calling {@link #commit()} or
+ * {@link #rollback()} will also close the session and no additional traversal can be executed on the
+ * {@link TraversalSource}. A fresh call to {@link #begin()} will be required to open a fresh session to work with.
+ * The default behavior of {@link #close()} is to commit the transaction.
+ */
+public class DriverRemoteTransaction implements Transaction, RemoteConnection {
+
+    private final DriverRemoteConnection sessionBasedConnection;
+
+    protected Consumer<Transaction> closeConsumer = CLOSE_BEHAVIOR.COMMIT;
+
+    public DriverRemoteTransaction(final DriverRemoteConnection sessionBasedConnection) {
+        this.sessionBasedConnection = sessionBasedConnection;
+    }
+
+    @Override
+    public <T extends TraversalSource> T begin(final Class<T> traversalSourceClass) {
+        if (!isOpen())
+            throw new IllegalStateException("Transaction cannot begin as the session is already closed - create a new Transaction");
+
+        try {
+            return traversalSourceClass.getConstructor(RemoteConnection.class).newInstance(this);
+        } catch (final Exception e) {
+            throw new IllegalStateException(e.getMessage(), e);
+        }
+    }
+
+    /**
+     * By virtue of creating a {@code DriverRemoteTransaction}, the transaction is considered open. There is no need
+     * to call this method. Calling it when the transaction is closed will result in exception.
+     */
+    @Override
+    public void open() {
+        // no need to issue a command to open the transaction, the server is already in such a state if the
+        if (!isOpen())
+            throw new IllegalStateException("Transaction cannot be opened as the session is already closed - create a new Transaction");
+    }
+
+    @Override
+    public void commit() {
+        closeRemoteTransaction(TX_COMMIT, "Transaction commit for %s failed");
+    }
+
+    @Override
+    public void rollback() {
+        closeRemoteTransaction(TX_ROLLBACK, "Transaction rollback for %s failed");
+    }
+
+    private void closeRemoteTransaction(final GraphOp closeTxWith, final String failureMsg) {
+        try {
+            // kinda weird but we hasNext() the graph command here to ensure that it runs to completion or
+            // else you don't guarantee that we have the returned NO_CONTENT message in hand before proceeding
+            // which could mean the transaction is still in the process of committing. not sure why iterate()
+            // doesn't quite work in this context.
+            this.sessionBasedConnection.submitAsync(closeTxWith.getBytecode()).join().hasNext();
+            this.sessionBasedConnection.close();
+        } catch (Exception ex) {
+            throw new RuntimeException(String.format(failureMsg, sessionBasedConnection.getSessionId()), ex);
+        }
+    }
+
+    @Override
+    public boolean isOpen() {
+        // for tx purposes closing is a good enough check
+        return !sessionBasedConnection.client.isClosing();
+    }
+
+    /**
+     * The default close behavior for this {@link Transaction} implementation is to {@link #commit()}.
+     */
+    @Override
+    public void close() {
+        this.closeConsumer.accept(this);
+    }
+
+    /**
+     * This {@link Transaction} implementation is not auto-managed and therefore this method is not supported.
+     */
+    @Override
+    public void readWrite() {
+        throw new UnsupportedOperationException("Remote transaction behaviors are not auto-managed - they are always manually controlled");
+    }
+
+    /**
+     * This {@link Transaction} implementation is not auto-managed and therefore this method is not supported.
+     */
+    @Override
+    public Transaction onReadWrite(final Consumer<Transaction> consumer) {
+        throw new UnsupportedOperationException("Remote transaction behaviors are not configurable - they are always manually controlled");
+    }
+
+    @Override
+    public Transaction onClose(final Consumer<Transaction> consumer) {
+        this.closeConsumer = consumer;
+        return this;
+    }
+
+    /**
+     * There is no support for remote transaction listeners.
+     */
+    @Override
+    public void addTransactionListener(final Consumer<Status> listener) {
+        throw new UnsupportedOperationException("Remote transactions cannot have listeners attached");
+    }
+
+    /**
+     * There is no support for remote transaction listeners.
+     */
+    @Override
+    public void removeTransactionListener(final Consumer<Status> listener) {
+        throw new UnsupportedOperationException("Remote transactions cannot have listeners attached");
+    }
+
+    /**
+     * There is no support for remote transaction listeners.
+     */
+    @Override
+    public void clearTransactionListeners() {
+        throw new UnsupportedOperationException("Remote transactions cannot have listeners attached");
+    }
+
+    /**
+     * It is not possible to have child transactions, therefore this method always returns {@link Transaction#NO_OP}.
+     */
+    @Override
+    public Transaction tx() {
+        return Transaction.NO_OP;
+    }
+
+    @Override
+    public <E> CompletableFuture<RemoteTraversal<?, E>> submitAsync(final Bytecode bytecode) throws RemoteConnectionException {
+        return sessionBasedConnection.submitAsync(bytecode);
+    }
+}
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversal.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversal.java
index e47b07b..54e7cc8 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversal.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversal.java
@@ -18,17 +18,15 @@
  */
 package org.apache.tinkerpop.gremlin.driver.remote;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.driver.Client;
 import org.apache.tinkerpop.gremlin.driver.Result;
 import org.apache.tinkerpop.gremlin.driver.ResultSet;
 import org.apache.tinkerpop.gremlin.process.remote.traversal.AbstractRemoteTraversal;
-import org.apache.tinkerpop.gremlin.process.remote.traversal.RemoteTraversalSideEffects;
 import org.apache.tinkerpop.gremlin.process.remote.traversal.RemoteTraverser;
 import org.apache.tinkerpop.gremlin.process.remote.traversal.step.map.RemoteStep;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.EmptyTraverser;
 import org.apache.tinkerpop.gremlin.structure.Element;
 import org.apache.tinkerpop.gremlin.structure.Graph;
@@ -53,7 +51,6 @@
 
     private final Iterator<Traverser.Admin<E>> traversers;
     private Traverser.Admin<E> lastTraverser = EmptyTraverser.instance();
-    private final RemoteTraversalSideEffects sideEffects;
 
     public DriverRemoteTraversal(final ResultSet rs, final Client client, final boolean attach, final Optional<Configuration> conf) {
         // attaching is really just for testing purposes. it doesn't make sense in any real-world scenario as it would
@@ -66,23 +63,6 @@
         } else {
             this.traversers = new TraverserIterator<>(rs.iterator());
         }
-
-        this.sideEffects = new DriverRemoteTraversalSideEffects(client,rs);
-    }
-
-    /**
-     * Gets a side-effect from the server. Do not call this method prior to completing the iteration of the
-     * {@link DriverRemoteTraversal} that spawned this as the side-effect will not be ready. Generally
-     * speaking, the common user would not get side-effects this way - they would use a call to {@code cap()}.
-     *
-     * @deprecated as of release 3.3.8, not directly replaced, see {@link Admin#getSideEffects()} for more information,
-     * but further note that this method is not being removed, but will not be functional for remote execution. Prefer
-     * {@link GraphTraversal#cap(String, String...)} to get side-effects as part of traversal iteration.
-     */
-    @Override
-    @Deprecated
-    public RemoteTraversalSideEffects getSideEffects() {
-        return this.sideEffects;
     }
 
     @Override
@@ -117,17 +97,6 @@
         }
     }
 
-    /**
-     * Releases server-side resources related to this traversal (i.e. clearing the side-effect cache of data related to
-     * this traversal.
-     */
-    @Override
-    public void close() throws Exception {
-        sideEffects.close();
-
-        // leave the client open as it is owned by the DriverRemoteConnection not the traversal or side-effects
-    }
-
     static class TraverserIterator<E> implements Iterator<Traverser.Admin<E>> {
 
         private final Iterator<Result> inner;
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversalSideEffects.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversalSideEffects.java
deleted file mode 100644
index baf54f3..0000000
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversalSideEffects.java
+++ /dev/null
@@ -1,193 +0,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.
- */
-package org.apache.tinkerpop.gremlin.driver.remote;
-
-import org.apache.commons.lang3.exception.ExceptionUtils;
-import org.apache.tinkerpop.gremlin.driver.Client;
-import org.apache.tinkerpop.gremlin.driver.Host;
-import org.apache.tinkerpop.gremlin.driver.Result;
-import org.apache.tinkerpop.gremlin.driver.ResultSet;
-import org.apache.tinkerpop.gremlin.driver.Tokens;
-import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
-import org.apache.tinkerpop.gremlin.process.remote.traversal.AbstractRemoteTraversalSideEffects;
-import org.apache.tinkerpop.gremlin.process.traversal.TraversalSideEffects;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.UUID;
-import java.util.concurrent.CompletableFuture;
-
-/**
- * Java driver implementation of {@link TraversalSideEffects}. This class is not thread safe.
- *
- * @author Stephen Mallette (http://stephen.genoprime.com)
- * @deprecated As of release 3.3.8, not directly replaced, prefer use of {@link GraphTraversal#cap(String, String...)}
- * to return the result as part of the traversal iteration.
- */
-@Deprecated
-public class DriverRemoteTraversalSideEffects extends AbstractRemoteTraversalSideEffects {
-
-    private final Client client;
-    private Set<String> keys = Collections.emptySet();
-    private final UUID serverSideEffect;
-    private final Host host;
-
-    private final Map<String, Object> sideEffects = new HashMap<>();
-
-    private boolean closed = false;
-    private boolean retrievedAllKeys = false;
-    private final CompletableFuture<Void> ready;
-    private final CompletableFuture<Map<String,Object>> statusAttributes;
-
-    /**
-     * @deprecated As of release 3.4.0, replaced by {@link #DriverRemoteTraversalSideEffects(Client, ResultSet)}
-     */
-    @Deprecated
-    public DriverRemoteTraversalSideEffects(final Client client, final UUID serverSideEffect, final Host host,
-                                            final CompletableFuture<Void> ready) {
-        this.client = client;
-        this.serverSideEffect = serverSideEffect;
-        this.host = host;
-        this.ready = ready;
-        this.statusAttributes = CompletableFuture.completedFuture(Collections.emptyMap());
-    }
-
-    public DriverRemoteTraversalSideEffects(final Client client, final ResultSet rs) {
-        this.client = client;
-        this.serverSideEffect = rs.getOriginalRequestMessage().getRequestId();
-        this.host = rs.getHost();
-        this.ready = rs.allItemsAvailableAsync();
-        this.statusAttributes = rs.statusAttributes();
-    }
-
-    /**
-     * Gets the status attributes from the response from the server. This method will block until all results have
-     * been retrieved.
-     */
-    public Map<String,Object> statusAttributes() {
-        // wait for the read to complete (i.e. iteration on the server) before allowing the caller to get the
-        // attribute. simply following the pattern from other methods here for now.
-        return statusAttributes.join();
-    }
-
-    @Override
-    public <V> V get(final String key) throws IllegalArgumentException {
-        // wait for the read to complete (i.e. iteration on the server) before allowing the caller to get the
-        // side-effect. calling prior to this will result in the side-effect not being found. of course, the
-        // bad part here is that the method blocks indefinitely waiting for the result, but it prevents the
-        // test failure problems that happen on slower systems. in practice, it's unlikely that a user would
-        // try to get a side-effect prior to iteration, but since the API allows it, this at least prevents
-        // the error.
-        ready.join();
-
-        if (!keys().contains(key)) throw TraversalSideEffects.Exceptions.sideEffectKeyDoesNotExist(key);
-
-        if (!sideEffects.containsKey(key)) {
-
-            if (closed) throw new IllegalStateException("Traversal has been closed - no new side-effects can be retrieved");
-
-            // specify the ARGS_HOST so that the LoadBalancingStrategy is subverted and the connection is forced
-            // from the specified host (i.e. the host from the previous request as that host will hold the side-effects)
-            final RequestMessage msg = RequestMessage.build(Tokens.OPS_GATHER)
-                    .addArg(Tokens.ARGS_SIDE_EFFECT, serverSideEffect)
-                    .addArg(Tokens.ARGS_SIDE_EFFECT_KEY, key)
-                    .addArg(Tokens.ARGS_HOST, host)
-                    .processor("traversal").create();
-            try {
-                final Result result = client.submitAsync(msg).get().all().get().get(0);
-                sideEffects.put(key, null == result ? null : result.getObject());
-            } catch (Exception ex) {
-                // we use to try to catch "no found" situations returned from the server here and then null the
-                // side-effect for the requested key. doesn't seem like there is a need for that now because calls
-                // to get() now initially trigger a call the keys() so you would know all of the keys available on
-                // the server and would validate them up front throwing sideEffectKeyDoesNotExist(key) which thus
-                // produces behavior similar to the non-remote side-effect implementations. if we get an exception
-                // here at this point then we likely have a legit error in communicating to the remote server.
-                throw new RuntimeException("Could not get side-effect for " + serverSideEffect + " with key of " + key, ex);
-            }
-        }
-
-        return (V) sideEffects.get(key);
-    }
-
-    @Override
-    public Set<String> keys() {
-        // wait for the read to complete (i.e. iteration on the server) before allowing the caller to get the
-        // side-effect. calling prior to this will result in the side-effect not being found. of course, the
-        // bad part here is that the method blocks indefinitely waiting for the result, but it prevents the
-        // test failure problems that happen on slower systems. in practice, it's unlikely that a user would
-        // try to get a side-effect prior to iteration, but since the API allows it, this at least prevents
-        // the error.
-        ready.join();
-
-        if (closed && !retrievedAllKeys) throw new IllegalStateException("Traversal has been closed - side-effect keys cannot be retrieved");
-
-        if (!retrievedAllKeys) {
-            // specify the ARGS_HOST so that the LoadBalancingStrategy is subverted and the connection is forced
-            // from the specified host (i.e. the host from the previous request as that host will hold the side-effects)
-            final RequestMessage msg = RequestMessage.build(Tokens.OPS_KEYS)
-                    .addArg(Tokens.ARGS_SIDE_EFFECT, serverSideEffect)
-                    .addArg(Tokens.ARGS_HOST, host)
-                    .processor("traversal").create();
-            try {
-                if (keys.equals(Collections.emptySet()))
-                    keys = new HashSet<>();
-
-                client.submitAsync(msg).get().all().get().forEach(r -> keys.add(r.getString()));
-
-                // only need to retrieve all keys once
-                retrievedAllKeys = true;
-            } catch (Exception ex) {
-                final Throwable root = ExceptionUtils.getRootCause(ex);
-                throw new RuntimeException("Could not get keys", null == root ? ex : root);
-            }
-        }
-
-        return keys;
-    }
-
-    @Override
-    public void close() throws Exception {
-        if (!closed) {
-            final RequestMessage msg = RequestMessage.build(Tokens.OPS_CLOSE)
-                    .addArg(Tokens.ARGS_SIDE_EFFECT, serverSideEffect)
-                    .addArg(Tokens.ARGS_HOST, host)
-                    .processor("traversal").create();
-            try {
-                client.submitAsync(msg).get();
-                closed = true;
-            } catch (Exception ex) {
-                final Throwable root = ExceptionUtils.getRootCause(ex);
-                throw new RuntimeException("Error on closing side effects", null == root ? ex : root);
-            }
-        }
-    }
-
-    @Override
-    public String toString() {
-        // have to override the implementation from TraversalSideEffects because it relies on calls to keys() as
-        // calling that too early can cause unintended failures (i.e. in the debugger, toString() gets called when
-        // introspecting the object from the moment of construction).
-        return "sideEffects[size:" + keys.size() + "]";
-    }
-}
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractGraphSONMessageSerializerV1d0.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractGraphSONMessageSerializerV1d0.java
index 72eba72..76a1808 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractGraphSONMessageSerializerV1d0.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractGraphSONMessageSerializerV1d0.java
@@ -50,7 +50,7 @@
 /**
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
-public abstract class AbstractGraphSONMessageSerializerV1d0 extends AbstractMessageSerializer {
+public abstract class AbstractGraphSONMessageSerializerV1d0 extends AbstractMessageSerializer<ObjectMapper> {
     private static final Logger logger = LoggerFactory.getLogger(AbstractGraphSONMessageSerializerV1d0.class);
 
     protected ObjectMapper mapper;
@@ -154,6 +154,11 @@
                 .version(GraphSONVersion.V1_0);
     }
 
+    @Override
+    public ObjectMapper getMapper() {
+        return this.mapper;
+    }
+
     public final static class GremlinServerModule extends SimpleModule {
         public GremlinServerModule() {
             super("graphson-gremlin-server");
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractGraphSONMessageSerializerV2d0.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractGraphSONMessageSerializerV2d0.java
index b085cb6..5f2c220 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractGraphSONMessageSerializerV2d0.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractGraphSONMessageSerializerV2d0.java
@@ -48,7 +48,7 @@
 /**
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
-public abstract class AbstractGraphSONMessageSerializerV2d0 extends AbstractMessageSerializer {
+public abstract class AbstractGraphSONMessageSerializerV2d0 extends AbstractMessageSerializer<ObjectMapper> {
     private static final Logger logger = LoggerFactory.getLogger(AbstractGraphSONMessageSerializerV2d0.class);
 
     protected ObjectMapper mapper;
@@ -145,6 +145,11 @@
                 .version(GraphSONVersion.V2_0);
     }
 
+    @Override
+    public ObjectMapper getMapper() {
+        return this.mapper;
+    }
+
     public final static class GremlinServerModule extends SimpleModule {
         public GremlinServerModule() {
             super("graphson-gremlin-server");
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractGryoMessageSerializerV1d0.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractGryoMessageSerializerV1d0.java
index 799b3d9..368b6bb 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractGryoMessageSerializerV1d0.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractGryoMessageSerializerV1d0.java
@@ -50,7 +50,7 @@
  * @deprecated As of release 3.4.3, replaced by {@link GraphBinaryMessageSerializerV1}.
  */
 @Deprecated
-public abstract class AbstractGryoMessageSerializerV1d0 extends AbstractMessageSerializer {
+public abstract class AbstractGryoMessageSerializerV1d0 extends AbstractMessageSerializer<Kryo> {
     private GryoMapper gryoMapper;
     private ThreadLocal<Kryo> kryoThreadLocal = new ThreadLocal<Kryo>() {
         @Override
@@ -88,6 +88,11 @@
     }
 
     @Override
+    public Kryo getMapper() {
+        return kryoThreadLocal.get();
+    }
+
+    @Override
     public final void configure(final Map<String, Object> config, final Map<String, Graph> graphs) {
         final GryoMapper.Builder builder = GryoMapper.build().version(GryoVersion.V1_0);
         addIoRegistries(config, builder);
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractGryoMessageSerializerV3d0.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractGryoMessageSerializerV3d0.java
index 2efb4a3..0affc90 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractGryoMessageSerializerV3d0.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractGryoMessageSerializerV3d0.java
@@ -47,7 +47,7 @@
  * @deprecated As of release 3.4.3, replaced by {@link GraphBinaryMessageSerializerV1}.
  */
 @Deprecated
-public abstract class AbstractGryoMessageSerializerV3d0 extends AbstractMessageSerializer {
+public abstract class AbstractGryoMessageSerializerV3d0 extends AbstractMessageSerializer<Kryo> {
     private GryoMapper gryoMapper;
     private ThreadLocal<Kryo> kryoThreadLocal = new ThreadLocal<Kryo>() {
         @Override
@@ -74,6 +74,11 @@
         this.gryoMapper = kryo;
     }
 
+    @Override
+    public Kryo getMapper() {
+        return kryoThreadLocal.get();
+    }
+
     /**
      * Called from the {@link #configure(Map, Map)} method right before the call to create the builder. Sub-classes
      * can choose to alter the builder or completely replace it.
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractMessageSerializer.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractMessageSerializer.java
index 59d0aad..50124a6 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractMessageSerializer.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractMessageSerializer.java
@@ -33,7 +33,7 @@
  *
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
-public abstract class AbstractMessageSerializer implements MessageSerializer {
+public abstract class AbstractMessageSerializer<M> implements MessageSerializer<M> {
     public static final String TOKEN_IO_REGISTRIES = "ioRegistries";
 
     /**
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphBinaryMessageSerializerV1.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphBinaryMessageSerializerV1.java
index bf4e76f..2eea896 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphBinaryMessageSerializerV1.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphBinaryMessageSerializerV1.java
@@ -23,6 +23,7 @@
 import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
 import org.apache.tinkerpop.gremlin.structure.io.binary.GraphBinaryIo;
+import org.apache.tinkerpop.gremlin.structure.io.binary.GraphBinaryMapper;
 import org.apache.tinkerpop.gremlin.structure.io.binary.GraphBinaryReader;
 import org.apache.tinkerpop.gremlin.structure.io.binary.GraphBinaryWriter;
 import org.apache.tinkerpop.gremlin.driver.ser.binary.RequestMessageSerializer;
@@ -42,7 +43,7 @@
 
 import static java.nio.charset.StandardCharsets.UTF_8;
 
-public class GraphBinaryMessageSerializerV1 extends AbstractMessageSerializer {
+public class GraphBinaryMessageSerializerV1 extends AbstractMessageSerializer<GraphBinaryMapper> {
 
     public static final String TOKEN_CUSTOM = "custom";
     public static final String TOKEN_BUILDER = "builder";
@@ -57,6 +58,7 @@
     private GraphBinaryWriter writer;
     private RequestMessageSerializer requestSerializer;
     private ResponseMessageSerializer responseSerializer;
+    private GraphBinaryMapper mapper;
 
     /**
      * Creates a new instance of the message serializer using the default type serializers.
@@ -68,6 +70,7 @@
     public GraphBinaryMessageSerializerV1(final TypeSerializerRegistry registry) {
         reader = new GraphBinaryReader(registry);
         writer = new GraphBinaryWriter(registry);
+        mapper = new GraphBinaryMapper(writer, reader);
 
         requestSerializer = new RequestMessageSerializer();
         responseSerializer = new ResponseMessageSerializer();
@@ -78,19 +81,23 @@
     }
 
     @Override
+    public GraphBinaryMapper getMapper() {
+        return mapper;
+    }
+
+    @Override
     public void configure(final Map<String, Object> config, final Map<String, Graph> graphs) {
         final String builderClassName = (String) config.get(TOKEN_BUILDER);
         final TypeSerializerRegistry.Builder builder;
 
         if (builderClassName != null) {
             try {
-                Class<?> clazz = Class.forName(builderClassName);
-                Constructor<?> ctor = clazz.getConstructor();
+                final Class<?> clazz = Class.forName(builderClassName);
+                final Constructor<?> ctor = clazz.getConstructor();
                 builder = (TypeSerializerRegistry.Builder) ctor.newInstance();
             } catch (Exception ex) {
                 throw new IllegalStateException(ex);
             }
-
         } else {
             builder = TypeSerializerRegistry.build();
         }
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV1d0.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV1d0.java
index 58dbbdf..d3a15f5 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV1d0.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV1d0.java
@@ -24,6 +24,7 @@
 import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper;
 import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONVersion;
 import org.apache.tinkerpop.gremlin.structure.io.graphson.TypeInfo;
+import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -36,7 +37,7 @@
  *
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
-public final class GraphSONMessageSerializerV1d0 extends AbstractGraphSONMessageSerializerV1d0 implements MessageTextSerializer {
+public final class GraphSONMessageSerializerV1d0 extends AbstractGraphSONMessageSerializerV1d0 implements MessageTextSerializer<ObjectMapper> {
     private static final Logger logger = LoggerFactory.getLogger(GraphSONMessageSerializerV1d0.class);
     private static final String MIME_TYPE = SerTokens.MIME_JSON;
 
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0.java
index e860dee..6717a00 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0.java
@@ -25,6 +25,7 @@
 import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONVersion;
 import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONXModuleV2d0;
 import org.apache.tinkerpop.gremlin.structure.io.graphson.TypeInfo;
+import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -37,7 +38,7 @@
  *
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
-public final class GraphSONMessageSerializerV2d0 extends AbstractGraphSONMessageSerializerV2d0 implements MessageTextSerializer {
+public final class GraphSONMessageSerializerV2d0 extends AbstractGraphSONMessageSerializerV2d0 implements MessageTextSerializer<ObjectMapper> {
     private static final Logger logger = LoggerFactory.getLogger(GraphSONMessageSerializerV2d0.class);
     private static final String MIME_TYPE = SerTokens.MIME_GRAPHSON_V2D0;
 
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV3d0.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV3d0.java
index 9547b3d..da3eea7 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV3d0.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV3d0.java
@@ -23,6 +23,7 @@
 import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper;
 import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONVersion;
 import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONXModuleV3d0;
+import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -33,7 +34,7 @@
  *
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
-public final class GraphSONMessageSerializerV3d0 extends AbstractGraphSONMessageSerializerV2d0 implements MessageTextSerializer {
+public final class GraphSONMessageSerializerV3d0 extends AbstractGraphSONMessageSerializerV2d0 implements MessageTextSerializer<ObjectMapper> {
     private static final Logger logger = LoggerFactory.getLogger(GraphSONMessageSerializerV3d0.class);
     private static final String MIME_TYPE = SerTokens.MIME_GRAPHSON_V3D0;
 
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/MessageTextSerializer.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/MessageTextSerializer.java
index 912c786..289d56d 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/MessageTextSerializer.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/MessageTextSerializer.java
@@ -30,7 +30,7 @@
  *
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
-public interface MessageTextSerializer extends MessageSerializer {
+public interface MessageTextSerializer<M> extends MessageSerializer<M> {
     public String serializeResponseAsString(final ResponseMessage responseMessage) throws SerializationException;
 
     public String serializeRequestAsString(final RequestMessage requestMessage) throws SerializationException;
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/Serializers.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/Serializers.java
index 04f6b7c..70c50f3 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/Serializers.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/Serializers.java
@@ -27,6 +27,7 @@
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
 public enum Serializers {
+
     /**
      * GraphSON 3.0.
      */
@@ -64,7 +65,7 @@
         return value;
     }
 
-    public MessageSerializer simpleInstance() {
+    public MessageSerializer<?> simpleInstance() {
         switch (value) {
             case SerTokens.MIME_JSON:
                 return new GraphSONMessageSerializerV3d0();
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/simple/AbstractClient.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/simple/AbstractClient.java
index e991e3e..270277b 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/simple/AbstractClient.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/simple/AbstractClient.java
@@ -30,6 +30,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
 import java.util.function.Consumer;
 
 /**
@@ -41,7 +42,7 @@
 
     public AbstractClient(final String threadPattern) {
         final BasicThreadFactory threadFactory = new BasicThreadFactory.Builder().namingPattern(threadPattern).build();
-        group = new NioEventLoopGroup(Runtime.getRuntime().availableProcessors(), threadFactory);
+        group = new NioEventLoopGroup(1, threadFactory);
     }
 
     public abstract void writeAndFlush(final RequestMessage requestMessage) throws Exception;
@@ -54,7 +55,10 @@
 
     @Override
     public List<ResponseMessage> submit(final RequestMessage requestMessage) throws Exception {
-        return submitAsync(requestMessage).get();
+        // this is just a test client to force certain behaviors of the server. hanging tests are a pain to deal with
+        // especially in travis as it's not always clear where the hang is. a few reasonable timeouts might help
+        // make debugging easier when we look at logs
+        return submitAsync(requestMessage).get(180, TimeUnit.SECONDS);
     }
 
     @Override
@@ -68,7 +72,7 @@
             results.add(response);
 
             // check if the current message is terminating - if it is then we can mark complete
-            if (!response.getStatus().getCode().equals(ResponseStatusCode.PARTIAL_CONTENT)) {
+            if (response.getStatus().getCode().isFinalResponse()) {
                 f.complete(results);
             }
         };
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/simple/NioClient.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/simple/NioClient.java
deleted file mode 100644
index 3904b20..0000000
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/simple/NioClient.java
+++ /dev/null
@@ -1,92 +0,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.
- */
-package org.apache.tinkerpop.gremlin.driver.simple;
-
-import io.netty.buffer.PooledByteBufAllocator;
-import io.netty.channel.ChannelOption;
-import org.apache.tinkerpop.gremlin.driver.MessageSerializer;
-import org.apache.tinkerpop.gremlin.driver.handler.NioGremlinRequestEncoder;
-import org.apache.tinkerpop.gremlin.driver.handler.NioGremlinResponseDecoder;
-import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
-import io.netty.bootstrap.Bootstrap;
-import io.netty.channel.Channel;
-import io.netty.channel.ChannelInitializer;
-import io.netty.channel.ChannelPipeline;
-import io.netty.channel.socket.SocketChannel;
-import io.netty.channel.socket.nio.NioSocketChannel;
-import org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0;
-
-import java.io.IOException;
-import java.net.URI;
-
-/**
- * A simple, non-thread safe Gremlin Server client using NIO.  Typical use is for testing and demonstration.
- *
- * @author Stephen Mallette (http://stephen.genoprime.com)
- * @deprecated As of release 3.3.10, not replaced, use {@link WebSocketClient}.
- */
-@Deprecated
-public class NioClient extends AbstractClient {
-    private final Channel channel;
-
-    public NioClient() {
-        this(URI.create("gs://localhost:8182"));
-    }
-
-    public NioClient(final URI uri) {
-        super("nio-client-%d");
-        final Bootstrap b = new Bootstrap().group(group);
-        b.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
-
-        try {
-            final MessageSerializer serializer = new GryoMessageSerializerV3d0();
-            b.channel(NioSocketChannel.class)
-                    .handler(new ChannelInitializer<SocketChannel>() {
-                        @Override
-                        protected void initChannel(final SocketChannel ch) {
-                            final ChannelPipeline p = ch.pipeline();
-                            p.addLast(
-                                    new NioGremlinResponseDecoder(serializer),
-                                    new NioGremlinRequestEncoder(true, serializer),
-                                    callbackResponseHandler);
-                        }
-                    });
-
-            channel = b.connect(uri.getHost(), uri.getPort()).sync().channel();
-        } catch (Exception ex) {
-            throw new RuntimeException(ex);
-        }
-    }
-
-    @Override
-    public void writeAndFlush(final RequestMessage requestMessage) throws Exception {
-        channel.writeAndFlush(requestMessage).get();
-    }
-
-    @Override
-    public void close() throws IOException {
-        try {
-            channel.close().get();
-        } catch (Exception ignored) {
-
-        } finally {
-            group.shutdownGracefully().awaitUninterruptibly();
-        }
-    }
-}
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/simple/WebSocketClient.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/simple/WebSocketClient.java
index 8ef48b6..767f5a8 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/simple/WebSocketClient.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/simple/WebSocketClient.java
@@ -36,10 +36,14 @@
 import io.netty.handler.codec.http.HttpObjectAggregator;
 import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory;
 import io.netty.handler.codec.http.websocketx.WebSocketVersion;
-import org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0;
+import org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1;
+import org.apache.tinkerpop.gremlin.structure.io.binary.GraphBinaryMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 import java.net.URI;
+import java.util.concurrent.TimeUnit;
 
 /**
  * A simple, non-thread safe Gremlin Server client using websockets.  Typical use is for testing and demonstration.
@@ -47,6 +51,7 @@
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
 public class WebSocketClient extends AbstractClient {
+    private static final Logger logger = LoggerFactory.getLogger(WebSocketClient.class);
     private final Channel channel;
 
     public WebSocketClient() {
@@ -65,7 +70,7 @@
         try {
             final WebSocketClientHandler wsHandler = new WebSocketClientHandler(WebSocketClientHandshakerFactory.newHandshaker(
                     uri, WebSocketVersion.V13, null, true, EmptyHttpHeaders.INSTANCE, 65536), 10000);
-            final MessageSerializer serializer = new GryoMessageSerializerV3d0();
+            final MessageSerializer<GraphBinaryMapper> serializer = new GraphBinaryMessageSerializerV1();
             b.channel(NioSocketChannel.class)
                     .handler(new ChannelInitializer<SocketChannel>() {
                         @Override
@@ -82,7 +87,7 @@
                     });
 
             channel = b.connect(uri.getHost(), uri.getPort()).sync().channel();
-            wsHandler.handshakeFuture().get();
+            wsHandler.handshakeFuture().get(30, TimeUnit.SECONDS);
         } catch (Exception ex) {
             throw new RuntimeException(ex);
         }
@@ -90,17 +95,19 @@
 
     @Override
     public void writeAndFlush(final RequestMessage requestMessage) throws Exception {
-        channel.writeAndFlush(requestMessage).get();
+        channel.writeAndFlush(requestMessage);
     }
 
     @Override
     public void close() throws IOException {
         try {
-            channel.close().get();
-        } catch (Exception ignored) {
-
+            channel.close().get(30, TimeUnit.SECONDS);
+        } catch (Exception ex) {
+            logger.error("Failure closing simple WebSocketClient", ex);
         } finally {
-            group.shutdownGracefully().awaitUninterruptibly();
+            if (!group.shutdownGracefully().awaitUninterruptibly(30, TimeUnit.SECONDS)) {
+                logger.error("Could not cleanly shutdown thread pool on WebSocketClient");
+            }
         }
     }
 }
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/util/ProfilingApplication.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/util/ProfilingApplication.java
index b3d20d7..3766460 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/util/ProfilingApplication.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/util/ProfilingApplication.java
@@ -158,7 +158,7 @@
         final int workerPoolSize = Integer.parseInt(options.getOrDefault("workerPoolSize", "2").toString());
         final int tooSlowThreshold = Integer.parseInt(options.getOrDefault("tooSlowThreshold", "125").toString());
         final String channelizer = options.getOrDefault("channelizer", Channelizer.WebSocketChannelizer.class.getName()).toString();
-        final String serializer = options.getOrDefault("serializer", Serializers.GRYO_V1D0.name()).toString();
+        final String serializer = options.getOrDefault("serializer", Serializers.GRAPHBINARY_V1D0.name()).toString();
 
         final boolean exercise = Boolean.parseBoolean(options.getOrDefault("exercise", "false").toString());
         final String script = options.getOrDefault("script", "1+1").toString();
diff --git a/gremlin-driver/src/main/static/LICENSE b/gremlin-driver/src/main/static/LICENSE
new file mode 100644
index 0000000..c7f7809
--- /dev/null
+++ b/gremlin-driver/src/main/static/LICENSE
@@ -0,0 +1,234 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+========================================================================
+BSD-style Licenses
+========================================================================
+
+The Apache TinkerPop project bundles the following components under the BSD License:
+
+     jcabi-log (com.jcabi:jcabi-log:0.14 - http://www.jcabi.com/jcabi-log) - for details, see
+       - shaded to com.shaded.jcabi.log
+       - for details, see licenses/jcabi-log
+     jcabi-manifests 1.1 (com.jcabi:jcabi-manifests:1.1 - http://www.jcabi.com/jcabi-manifests)
+       - shaded to com.shaded.jcabi.manifests
+       - for details, see licenses/jcabi-manifests
+     Kryo (com.esotericsoftware:kryo-shaded:3.0.3 - https://github.com/EsotericSoftware/kryo)
+       - shaded to org.apache.tinkerpop.shaded.kryo
+       - for details, see licenses/kryo
+     minlog (com.esotericsoftware:minlog:1.3.0 - https://github.com/EsotericSoftware/minlog)
+       - shaded to org.apache.tinkerpop.shaded.minlog
+       - for details, see licenses/minlog
+
+========================================================================
+MIT Licenses
+========================================================================
+
+The Apache TinkerPop project bundles the following components under the MIT License:
+
+     SLF4J API Module (org.slf4j:slf4j-api:1.7.25 - http://www.slf4j.org)
+       - shaded to org.shaded.slf4j
+       - for details, see licenses/slf4j
+     SLF4J LOG4J-12 Binding (org.slf4j:slf4j-log4j12:1.7.25 - http://www.slf4j.org)
+       - shaded to org.shaded.slf4j
+       - for details, see licenses/slf4j
diff --git a/gremlin-driver/src/main/static/NOTICE b/gremlin-driver/src/main/static/NOTICE
new file mode 100644
index 0000000..bd9526e
--- /dev/null
+++ b/gremlin-driver/src/main/static/NOTICE
@@ -0,0 +1,28 @@
+Apache TinkerPop
+Copyright 2015-2021 The Apache Software Foundation.
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+------------------------------------------------------------------------
+HPPC 0.7.1
+------------------------------------------------------------------------
+HPPC borrowed code, ideas or both from:
+
+ * Apache Lucene, http://lucene.apache.org/
+   (Apache license)
+ * Fastutil, http://fastutil.di.unimi.it/
+   (Apache license)
+ * Koloboke, https://github.com/OpenHFT/Koloboke
+   (Apache license)
+
+------------------------------------------------------------------------
+JavaTuples 1.2
+------------------------------------------------------------------------
+Copyright (c) 2010, The JAVATUPLES team (http://www.javatuples.org)
+
+------------------------------------------------------------------------
+Netty 4.1.62
+------------------------------------------------------------------------
+Copyright 2014 The Netty Project
+
diff --git a/gremlin-driver/src/main/static/licenses/jcabi-log b/gremlin-driver/src/main/static/licenses/jcabi-log
new file mode 100644
index 0000000..ece789e
--- /dev/null
+++ b/gremlin-driver/src/main/static/licenses/jcabi-log
@@ -0,0 +1,27 @@
+Copyright (c) 2012-2015, jcabi.com
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met: 1) Redistributions of source code must retain the above
+copyright notice, this list of conditions and the following
+disclaimer. 2) Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following
+disclaimer in the documentation and/or other materials provided
+with the distribution. 3) Neither the name of the jcabi.com nor
+the names of its contributors may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/gremlin-driver/src/main/static/licenses/jcabi-manifests b/gremlin-driver/src/main/static/licenses/jcabi-manifests
new file mode 100644
index 0000000..ece789e
--- /dev/null
+++ b/gremlin-driver/src/main/static/licenses/jcabi-manifests
@@ -0,0 +1,27 @@
+Copyright (c) 2012-2015, jcabi.com
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met: 1) Redistributions of source code must retain the above
+copyright notice, this list of conditions and the following
+disclaimer. 2) Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following
+disclaimer in the documentation and/or other materials provided
+with the distribution. 3) Neither the name of the jcabi.com nor
+the names of its contributors may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/gremlin-driver/src/main/static/licenses/kryo b/gremlin-driver/src/main/static/licenses/kryo
new file mode 100644
index 0000000..3f6a160
--- /dev/null
+++ b/gremlin-driver/src/main/static/licenses/kryo
@@ -0,0 +1,10 @@
+Copyright (c) 2008, Nathan Sweet
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+    * Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/gremlin-driver/src/main/static/licenses/minlog b/gremlin-driver/src/main/static/licenses/minlog
new file mode 100644
index 0000000..3f6a160
--- /dev/null
+++ b/gremlin-driver/src/main/static/licenses/minlog
@@ -0,0 +1,10 @@
+Copyright (c) 2008, Nathan Sweet
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+    * Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ClusterBuilderTest.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ClusterBuilderTest.java
index 581f42d..32871e1 100644
--- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ClusterBuilderTest.java
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ClusterBuilderTest.java
@@ -52,8 +52,8 @@
                 {"minConnectionPoolSizeLteMax", Cluster.build().minConnectionPoolSize(100).maxConnectionPoolSize(99), "maxConnectionPoolSize cannot be less than minConnectionPoolSize"},
                 {"minConnectionPoolSizeLteMax", Cluster.build().minConnectionPoolSize(100).maxConnectionPoolSize(99), "maxConnectionPoolSize cannot be less than minConnectionPoolSize"},
                 {"maxConnectionPoolSize0", Cluster.build().maxWaitForConnection(0), "maxWaitForConnection must be greater than zero"},
-                {"maxWaitForSessionClose0", Cluster.build().maxWaitForSessionClose(0), "maxWaitForSessionClose must be greater than zero"},
-                {"maxWaitForSessionCloseNeg1", Cluster.build().maxWaitForSessionClose(-1), "maxWaitForSessionClose must be greater than zero"},
+                {"maxWaitForClose0", Cluster.build().maxWaitForClose(0), "maxWaitForClose must be greater than zero"},
+                {"maxWaitForCloseNeg1", Cluster.build().maxWaitForClose(-1), "maxWaitForClose must be greater than zero"},
                 {"maxContentLength0", Cluster.build().maxContentLength(0), "maxContentLength must be greater than zero"},
                 {"maxContentLengthNeg1", Cluster.build().maxContentLength(-1), "maxContentLength must be greater than zero"},
                 {"reconnectInterval0", Cluster.build().reconnectInterval(0), "reconnectInterval must be greater than zero"},
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/MockitoHamcrestMatcherAdapter.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/MockitoHamcrestMatcherAdapter.java
new file mode 100644
index 0000000..252d9a9
--- /dev/null
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/MockitoHamcrestMatcherAdapter.java
@@ -0,0 +1,51 @@
+/*
+ * 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.driver;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.mockito.ArgumentMatcher;
+import org.mockito.internal.matchers.apachecommons.ReflectionEquals;
+
+/**
+ * Adapts a Mockito {@code ArgumentMatcher} to a Hamcrest {@code Matcher} so that it can be used with the Hamcrest
+ * {@code assertThat}.
+ */
+public class MockitoHamcrestMatcherAdapter extends BaseMatcher {
+
+    private final ArgumentMatcher<Object> mockitoMatcher;
+
+    public MockitoHamcrestMatcherAdapter(final ArgumentMatcher<Object> mockitoMatcher) {
+        this.mockitoMatcher = mockitoMatcher;
+    }
+
+    public static MockitoHamcrestMatcherAdapter reflectionEquals(final Object wanted, final String... excludeFields) {
+        return new MockitoHamcrestMatcherAdapter(new ReflectionEquals(wanted, excludeFields));
+    }
+
+    @Override
+    public boolean matches(final Object o) {
+        return mockitoMatcher.matches(o);
+    }
+
+    @Override
+    public void describeTo(final Description description) {
+        description.appendValue(mockitoMatcher.toString());
+    }
+}
\ No newline at end of file
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ResultQueueTest.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ResultQueueTest.java
index 75afb74..4ca4664 100644
--- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ResultQueueTest.java
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ResultQueueTest.java
@@ -19,16 +19,12 @@
 package org.apache.tinkerpop.gremlin.driver;
 
 import org.apache.commons.lang3.exception.ExceptionUtils;
-import org.apache.tinkerpop.gremlin.process.remote.traversal.DefaultRemoteTraverser;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.BulkSet;
 import org.junit.Test;
 
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -153,7 +149,7 @@
     }
 
     @Test
-    public void shouldAwaitFailTheFutureOnMarkError() throws Exception {
+    public void shouldAwaitFailTheFutureOnMarkError() {
         final CompletableFuture<List<Result>> future = resultQueue.await(4);
         resultQueue.add(new Result("test1"));
         resultQueue.add(new Result("test2"));
@@ -298,128 +294,4 @@
             t.interrupt();
         }
     }
-
-    @Test
-    public void shouldHandleBulkSetSideEffects() throws Exception  {
-        final CompletableFuture<List<Result>> o = resultQueue.await(1);
-        assertThat(o.isDone(), is(false));
-
-        resultQueue.addSideEffect(Tokens.VAL_AGGREGATE_TO_BULKSET, new DefaultRemoteTraverser<>("brian", 2));
-        assertThat(o.isDone(), is(false));
-
-        resultQueue.addSideEffect(Tokens.VAL_AGGREGATE_TO_BULKSET, new DefaultRemoteTraverser<>("brian", 2));
-        assertThat(o.isDone(), is(false));
-
-        resultQueue.addSideEffect(Tokens.VAL_AGGREGATE_TO_BULKSET, new DefaultRemoteTraverser<>("belinda", 6));
-        assertThat(o.isDone(), is(false));
-
-        resultQueue.markComplete(ATTRIBUTES);
-
-        assertThat(o.isDone(), is(true));
-        final BulkSet<String> bulkSet = o.get().get(0).get(BulkSet.class);
-        assertEquals(4, bulkSet.get("brian"));
-        assertEquals(6, bulkSet.get("belinda"));
-
-        assertEquals("that", resultQueue.getStatusAttributes().get("this"));
-    }
-
-    @Test
-    public void shouldHandleListSideEffects() throws Exception {
-        final CompletableFuture<List<Result>> o = resultQueue.await(1);
-        assertThat(o.isDone(), is(false));
-
-        resultQueue.addSideEffect(Tokens.VAL_AGGREGATE_TO_LIST, "stephen");
-        assertThat(o.isDone(), is(false));
-
-        resultQueue.addSideEffect(Tokens.VAL_AGGREGATE_TO_LIST, "daniel");
-        assertThat(o.isDone(), is(false));
-
-        resultQueue.addSideEffect(Tokens.VAL_AGGREGATE_TO_LIST, "dave");
-        assertThat(o.isDone(), is(false));
-
-        resultQueue.markComplete(ATTRIBUTES);
-
-        assertThat(o.isDone(), is(true));
-        final List<String> list = o.get().get(0).get(ArrayList.class);
-        assertEquals("stephen", list.get(0));
-        assertEquals("daniel", list.get(1));
-        assertEquals("dave", list.get(2));
-
-        assertEquals("that", resultQueue.getStatusAttributes().get("this"));
-    }
-
-    @Test
-    public void shouldHandleSetSideEffects() throws Exception {
-        final CompletableFuture<List<Result>> o = resultQueue.await(1);
-        assertThat(o.isDone(), is(false));
-
-        resultQueue.addSideEffect(Tokens.VAL_AGGREGATE_TO_SET, "stephen");
-        assertThat(o.isDone(), is(false));
-
-        resultQueue.addSideEffect(Tokens.VAL_AGGREGATE_TO_SET, "daniel");
-        assertThat(o.isDone(), is(false));
-
-        resultQueue.addSideEffect(Tokens.VAL_AGGREGATE_TO_SET, "dave");
-        assertThat(o.isDone(), is(false));
-
-        resultQueue.markComplete(ATTRIBUTES);
-
-        assertThat(o.isDone(), is(true));
-        final Set<String> set = o.get().get(0).get(HashSet.class);
-        assertThat(set.contains("stephen"), is(true));
-        assertThat(set.contains("daniel"), is(true));
-        assertThat(set.contains("dave"), is(true));
-
-        assertEquals("that", resultQueue.getStatusAttributes().get("this"));
-    }
-
-    @Test
-    public void shouldHandleMapSideEffects() throws Exception {
-        final CompletableFuture<List<Result>> o = resultQueue.await(1);
-        assertThat(o.isDone(), is(false));
-
-        final Map<String,String> m = new HashMap<>();
-        m.put("s", "stephen");
-        m.put("m", "marko");
-        m.put("d", "daniel");
-
-        m.entrySet().forEach(e -> {
-            resultQueue.addSideEffect(Tokens.VAL_AGGREGATE_TO_MAP, e);
-            assertThat(o.isDone(), is(false));
-        });
-
-        resultQueue.markComplete(ATTRIBUTES);
-
-        assertThat(o.isDone(), is(true));
-        final Map<String, String> list = o.get().get(0).get(HashMap.class);
-        assertEquals("stephen", list.get("s"));
-        assertEquals("daniel", list.get("d"));
-        assertEquals("marko", list.get("m"));
-
-        assertEquals("that", resultQueue.getStatusAttributes().get("this"));
-    }
-
-
-    @Test
-    public void shouldHandleNotAggregateSideEffects() throws Exception  {
-        final CompletableFuture<List<Result>> o = resultQueue.await(1);
-        assertThat(o.isDone(), is(false));
-
-        final Map<String,String> m = new HashMap<>();
-        m.put("s", "stephen");
-        m.put("m", "marko");
-        m.put("d", "daniel");
-
-        resultQueue.addSideEffect(Tokens.VAL_AGGREGATE_TO_NONE, m);
-
-        resultQueue.markComplete(ATTRIBUTES);
-
-        assertThat(o.isDone(), is(true));
-        final Map<String, String> list = o.get().get(0).get(HashMap.class);
-        assertEquals("stephen", list.get("s"));
-        assertEquals("daniel", list.get("d"));
-        assertEquals("marko", list.get("m"));
-
-        assertEquals("that", resultQueue.getStatusAttributes().get("this"));
-    }
 }
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/SettingsTest.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/SettingsTest.java
index 1eec4a9..a373fde 100644
--- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/SettingsTest.java
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/SettingsTest.java
@@ -20,10 +20,10 @@
 
 import static org.hamcrest.core.Is.is;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
 import org.junit.Test;
 
 import java.util.Arrays;
@@ -47,10 +47,6 @@
         conf.setProperty("serializer.className", "my.serializers.MySerializer");
         conf.setProperty("serializer.config.any", "thing");
         conf.setProperty("connectionPool.enableSsl", true);
-        conf.setProperty("connectionPool.keyCertChainFile", "X.509");
-        conf.setProperty("connectionPool.keyFile", "PKCS#8");
-        conf.setProperty("connectionPool.keyPassword", "password1");
-        conf.setProperty("connectionPool.trustCertChainFile", "pem");
         conf.setProperty("connectionPool.keyStore", "server.jks");
         conf.setProperty("connectionPool.keyStorePassword", "password2");
         conf.setProperty("connectionPool.keyStoreType", "pkcs12");
@@ -87,10 +83,6 @@
         assertEquals("my.serializers.MySerializer", settings.serializer.className);
         assertEquals("thing", settings.serializer.config.get("any"));
         assertThat(settings.connectionPool.enableSsl, is(true));
-        assertEquals("X.509", settings.connectionPool.keyCertChainFile);
-        assertEquals("PKCS#8", settings.connectionPool.keyFile);
-        assertEquals("password1", settings.connectionPool.keyPassword);
-        assertEquals("pem", settings.connectionPool.trustCertChainFile);
         assertEquals("server.jks", settings.connectionPool.keyStore);
         assertEquals("password2", settings.connectionPool.keyStorePassword);
         assertEquals("pkcs12", settings.connectionPool.keyStoreType);
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteConnectionTest.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteConnectionTest.java
index 820a0d3..a161ddf 100644
--- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteConnectionTest.java
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteConnectionTest.java
@@ -42,7 +42,7 @@
                         with("y", 100).
                         with(Tokens.ARGS_BATCH_SIZE, 1000).
                         with(Tokens.REQUEST_ID, requestId).
-                        with(Tokens.ARGS_SCRIPT_EVAL_TIMEOUT, 100000L).
+                        with(Tokens.ARGS_EVAL_TIMEOUT, 100000L).
                         with(Tokens.ARGS_USER_AGENT, "test").
                         V().asAdmin().getBytecode());
         assertEquals(requestId, options.getOverrideRequestId().get());
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversalSideEffectsTest.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversalSideEffectsTest.java
deleted file mode 100644
index 4e6df93..0000000
--- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversalSideEffectsTest.java
+++ /dev/null
@@ -1,140 +0,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.
- */
-package org.apache.tinkerpop.gremlin.driver.remote;
-
-import org.apache.tinkerpop.gremlin.driver.AbstractResultQueueTest;
-import org.apache.tinkerpop.gremlin.driver.Client;
-import org.apache.tinkerpop.gremlin.driver.ResultSet;
-import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
-import org.apache.tinkerpop.gremlin.process.traversal.TraversalSideEffects;
-import org.junit.Test;
-import org.mockito.stubbing.Answer;
-
-import java.util.UUID;
-import java.util.concurrent.CompletableFuture;
-
-import static org.hamcrest.core.IsInstanceOf.instanceOf;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-/**
- * @author Stephen Mallette (http://stephen.genoprime.com)
- */
-public class DriverRemoteTraversalSideEffectsTest extends AbstractResultQueueTest {
-
-    @Test
-    public void shouldNotContactRemoteForKeysAfterCloseIsCalled() throws Exception {
-        final Client client = mock(Client.class);
-        mockClientForCall(client);
-        mockClientForCall(client);
-
-        final UUID sideEffectKey = UUID.fromString("31dec2c6-b214-4a6f-a68b-996608dce0d9");
-        final CompletableFuture<Void> ready = new CompletableFuture<>();
-        ready.complete(null);
-        final TraversalSideEffects sideEffects = new DriverRemoteTraversalSideEffects(client, sideEffectKey, null, ready);
-
-        assertEquals(1, sideEffects.keys().size());
-        sideEffects.close();
-
-        // call this again and again and it will only hit the cached keys - no more server calls
-        assertEquals(1, sideEffects.keys().size());
-        assertEquals(1, sideEffects.keys().size());
-        assertEquals(1, sideEffects.keys().size());
-        assertEquals(1, sideEffects.keys().size());
-
-        // once for the keys and once for the close message
-        verify(client, times(2)).submitAsync(any(RequestMessage.class));
-    }
-
-    @Test
-    public void shoudlNotContactRemoteForGetAfterCloseIsCalled() throws Exception {
-        final Client client = mock(Client.class);
-        mockClientForCall(client);
-        mockClientForCall(client);
-        final UUID sideEffectKey = UUID.fromString("31dec2c6-b214-4a6f-a68b-996608dce0d9");
-        final CompletableFuture<Void> ready = new CompletableFuture<>();
-        ready.complete(null);
-        final TraversalSideEffects sideEffects = new DriverRemoteTraversalSideEffects(client, sideEffectKey, null, ready);
-
-        assertNotNull(sideEffects.get("test-0"));
-        sideEffects.close();
-
-        // Side effect 'a' should be cached locally
-        assertNotNull(sideEffects.get("test-0"));
-        assertNotNull(sideEffects.get("test-0"));
-        assertNotNull(sideEffects.get("test-0"));
-
-        // Once for keys, once for get and once for close
-        verify(client, times(3)).submitAsync(any(RequestMessage.class));
-    }
-
-    @Test
-    public void shouldNotContactRemoteMoreThanOnceForClose() throws Exception {
-        final Client client = mock(Client.class);
-        mockClientForCall(client);
-
-        final UUID sideEffectKey = UUID.fromString("31dec2c6-b214-4a6f-a68b-996608dce0d9");
-        final CompletableFuture<Void> ready = new CompletableFuture<>();
-        ready.complete(null);
-        final TraversalSideEffects sideEffects = new DriverRemoteTraversalSideEffects(client, sideEffectKey, null, ready);
-
-        sideEffects.close();
-        sideEffects.close();
-        sideEffects.close();
-        sideEffects.close();
-        sideEffects.close();
-
-        try {
-            sideEffects.keys();
-            fail("The traversal is closed");
-        } catch (Exception ex) {
-            assertThat(ex, instanceOf(IllegalStateException.class));
-            assertEquals("Traversal has been closed - side-effect keys cannot be retrieved", ex.getMessage());
-        }
-
-        try {
-            sideEffects.get("a");
-            fail("The traversal is closed");
-        } catch (Exception ex) {
-            assertThat(ex, instanceOf(IllegalStateException.class));
-            assertEquals("Traversal has been closed - side-effect keys cannot be retrieved", ex.getMessage());
-        }
-
-        // once for the close message
-        verify(client, times(1)).submitAsync(any(RequestMessage.class));
-    }
-
-    private void mockClientForCall(final Client client) throws Exception {
-        // the return is just generic garbage from addToQueue for any call to submitAsync().
-        when(client.submitAsync(any(RequestMessage.class))).thenAnswer((Answer<Object>) invocationOnMock -> {
-            final ResultSet returnedResultSet = new ResultSet(resultQueue, pool, readCompleted, RequestMessage.build("traversal").create(), null);
-            addToQueue(1, 0, true, true, 1);
-            final CompletableFuture<ResultSet> returnedFuture = new CompletableFuture<>();
-            returnedFuture.complete(returnedResultSet);
-            return returnedFuture;
-        });
-    }
-}
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerGremlinV1d0Test.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerGremlinV1d0Test.java
index f9362be..8cba236 100644
--- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerGremlinV1d0Test.java
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerGremlinV1d0Test.java
@@ -34,6 +34,7 @@
 import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerFactory;
 import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
+import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
 import org.apache.tinkerpop.shaded.jackson.databind.util.StdDateFormat;
 import org.junit.Test;
 
@@ -60,7 +61,7 @@
     private ResponseMessage.Builder responseMessageBuilder = ResponseMessage.build(requestId);
     private static ByteBufAllocator allocator = UnpooledByteBufAllocator.DEFAULT;
 
-    public MessageSerializer serializer = new GraphSONMessageSerializerGremlinV1d0();
+    public MessageSerializer<ObjectMapper> serializer = new GraphSONMessageSerializerGremlinV1d0();
 
     @Test
     public void shouldSerializeIterable() throws Exception {
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerGremlinV2d0Test.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerGremlinV2d0Test.java
index 7d3e702..21970be 100644
--- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerGremlinV2d0Test.java
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerGremlinV2d0Test.java
@@ -36,6 +36,7 @@
 import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerFactory;
 import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
+import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
 import org.apache.tinkerpop.shaded.jackson.databind.util.StdDateFormat;
 import org.junit.Assert;
 import org.junit.Test;
@@ -66,7 +67,7 @@
     private final ResponseMessage.Builder responseMessageBuilder = ResponseMessage.build(requestId);
     private final static ByteBufAllocator allocator = UnpooledByteBufAllocator.DEFAULT;
 
-    public final MessageSerializer serializer = new GraphSONMessageSerializerGremlinV2d0();
+    public final MessageSerializer<ObjectMapper> serializer = new GraphSONMessageSerializerGremlinV2d0();
 
     @Test
     public void shouldSerializeIterable() throws Exception {
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0Test.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0Test.java
index dc23179..897b759 100644
--- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0Test.java
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0Test.java
@@ -588,7 +588,7 @@
         logger.setLevel(previousLevel);
     }
 
-    private ResponseMessage convert(final Object toSerialize, MessageSerializer serializer) throws SerializationException {
+    private ResponseMessage convert(final Object toSerialize, MessageSerializer<?> serializer) throws SerializationException {
         final ByteBuf bb = serializer.serializeResponseAsBinary(responseMessageBuilder.result(toSerialize).create(), allocator);
         return serializer.deserializeResponse(bb);
     }
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV3d0Test.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV3d0Test.java
index b9ca43c..29de3c3 100644
--- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV3d0Test.java
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV3d0Test.java
@@ -40,6 +40,7 @@
 import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 import org.apache.tinkerpop.shaded.jackson.databind.JsonMappingException;
+import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
 import org.junit.Test;
 
 import java.util.ArrayList;
@@ -68,7 +69,7 @@
     private final ResponseMessage.Builder responseMessageBuilder = ResponseMessage.build(requestId);
     private final static ByteBufAllocator allocator = UnpooledByteBufAllocator.DEFAULT;
 
-    public final MessageSerializer serializer = new GraphSONMessageSerializerV3d0();
+    public final MessageSerializer<ObjectMapper> serializer = new GraphSONMessageSerializerV3d0();
 
     @Test
     public void shouldSerializeIterable() throws Exception {
@@ -386,7 +387,7 @@
         assertEquals(ResponseStatusCode.SUCCESS, response.getStatus().getCode());
     }
 
-    private ResponseMessage convert(final Object toSerialize, MessageSerializer serializer) throws SerializationException {
+    private ResponseMessage convert(final Object toSerialize, MessageSerializer<?> serializer) throws SerializationException {
         final ByteBuf bb = serializer.serializeResponseAsBinary(responseMessageBuilder.result(toSerialize).create(), allocator);
         return serializer.deserializeResponse(bb);
     }
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GryoLiteMessageSerializerV1d0Test.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GryoLiteMessageSerializerV1d0Test.java
index fe1ce63..ffc3522 100644
--- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GryoLiteMessageSerializerV1d0Test.java
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GryoLiteMessageSerializerV1d0Test.java
@@ -34,6 +34,7 @@
 import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerFactory;
 import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
+import org.apache.tinkerpop.shaded.kryo.Kryo;
 import org.junit.Test;
 
 import java.util.ArrayList;
@@ -58,7 +59,7 @@
     private ResponseMessage.Builder responseMessageBuilder = ResponseMessage.build(requestId);
     private static ByteBufAllocator allocator = UnpooledByteBufAllocator.DEFAULT;
 
-    public MessageSerializer binarySerializer = new GryoLiteMessageSerializerV1d0();
+    public MessageSerializer<Kryo> binarySerializer = new GryoLiteMessageSerializerV1d0();
 
     @Test
     public void shouldSerializeEdge() throws Exception {
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GryoMessageSerializerV1d0Test.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GryoMessageSerializerV1d0Test.java
index eba54a0..ea8c197 100644
--- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GryoMessageSerializerV1d0Test.java
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GryoMessageSerializerV1d0Test.java
@@ -91,7 +91,7 @@
     public String name;
 
     @Parameterized.Parameter(value = 1)
-    public Supplier<MessageSerializer> serializerSupplier;
+    public Supplier<MessageSerializer<?>> serializerSupplier;
 
     private static final Map<String, Object> configForText = new HashMap<String, Object>() {{
         put(GryoMessageSerializerV1d0.TOKEN_SERIALIZE_RESULT_TO_STRING, true);
@@ -107,7 +107,7 @@
             put(GryoMessageSerializerV1d0.TOKEN_IO_REGISTRIES, Collections.singletonList(ColorIoRegistry.class.getName()));
         }};
 
-        final MessageSerializer serializer = serializerSupplier.get();
+        final MessageSerializer<?> serializer = serializerSupplier.get();
         serializer.configure(config, null);
 
         final ResponseMessage toSerialize = ResponseMessage.build(requestId).result(Color.RED).create();
@@ -124,7 +124,7 @@
             put(GryoMessageSerializerV1d0.TOKEN_IO_REGISTRIES, Collections.singletonList(ColorIoRegistryInstance.class.getName()));
         }};
 
-        final MessageSerializer serializer = serializerSupplier.get();
+        final MessageSerializer<?> serializer = serializerSupplier.get();
         serializer.configure(config, null);
 
         final ResponseMessage toSerialize = ResponseMessage.build(requestId).result(Color.RED).create();
@@ -141,7 +141,7 @@
             put(GryoMessageSerializerV1d0.TOKEN_IO_REGISTRIES, Collections.singletonList(ColorIoRegistryGetInstance.class.getName()));
         }};
 
-        final MessageSerializer serializer = serializerSupplier.get();
+        final MessageSerializer<?> serializer = serializerSupplier.get();
         serializer.configure(config, null);
 
         final ResponseMessage toSerialize = ResponseMessage.build(requestId).result(Color.RED).create();
@@ -158,7 +158,7 @@
             put(GryoMessageSerializerV1d0.TOKEN_CLASS_RESOLVER_SUPPLIER, ErrorOnlyClassResolverSupplier.class.getName());
         }};
 
-        final MessageSerializer serializer = serializerSupplier.get();
+        final MessageSerializer<?> serializer = serializerSupplier.get();
         serializer.configure(config, null);
 
         try {
@@ -175,7 +175,7 @@
             put(GryoMessageSerializerV1d0.TOKEN_CLASS_RESOLVER_SUPPLIER, ErrorOnlyClassResolverSupplierAsInstance.class.getName());
         }};
 
-        final MessageSerializer serializer = serializerSupplier.get();
+        final MessageSerializer<?> serializer = serializerSupplier.get();
         serializer.configure(config, null);
 
         try {
@@ -192,7 +192,7 @@
             put(GryoMessageSerializerV1d0.TOKEN_CLASS_RESOLVER_SUPPLIER, ErrorOnlyClassResolverSupplierAsGetInstance.class.getName());
         }};
 
-        final MessageSerializer serializer = serializerSupplier.get();
+        final MessageSerializer<?> serializer = serializerSupplier.get();
         serializer.configure(config, null);
 
         try {
@@ -362,7 +362,7 @@
                 .statusMessage("worked")
                 .create();
 
-        final MessageSerializer serializer = serializerSupplier.get();
+        final MessageSerializer<?> serializer = serializerSupplier.get();
         final ByteBuf bb = serializer.serializeResponseAsBinary(response, allocator);
         final ResponseMessage deserialized = serializer.deserializeResponse(bb);
 
@@ -396,7 +396,7 @@
                 .statusMessage("worked")
                 .create();
 
-        final MessageSerializer binarySerializerWithSmallBuffer = new GryoMessageSerializerV1d0();
+        final MessageSerializer<Kryo> binarySerializerWithSmallBuffer = new GryoMessageSerializerV1d0();
         final Map<String, Object> configWithSmallBuffer = new HashMap<String, Object>() {{
             put("bufferSize", 1);
         }};
@@ -431,7 +431,7 @@
                 .statusMessage("worked")
                 .create();
 
-        final MessageSerializer binarySerializerWithSmallBuffer = new GryoMessageSerializerV1d0();
+        final MessageSerializer<Kryo> binarySerializerWithSmallBuffer = new GryoMessageSerializerV1d0();
         final Map<String, Object> configWithSmallBuffer = new HashMap<String, Object>() {{
             // set to bufferSize < total message size but still greater than any individual object requires
             put("bufferSize", 50);
@@ -453,7 +453,7 @@
                 .addArg("test", "this")
                 .create();
 
-        final MessageSerializer serializer = serializerSupplier.get();
+        final MessageSerializer<?> serializer = serializerSupplier.get();
         final ByteBuf bb = serializer.serializeRequestAsBinary(request, allocator);
         final int mimeLen = bb.readByte();
         bb.readBytes(new byte[mimeLen]);
@@ -475,7 +475,7 @@
                 .addArg("test", "this")
                 .create();
 
-        final MessageSerializer binarySerializerWithSmallBuffer = new GryoMessageSerializerV1d0();
+        final MessageSerializer<Kryo> binarySerializerWithSmallBuffer = new GryoMessageSerializerV1d0();
         final Map<String, Object> configWithSmallBuffer = new HashMap<String, Object>() {{
             put("bufferSize", 1);
         }};
@@ -500,7 +500,7 @@
                 .addArg("test", "this")
                 .create();
 
-        final MessageSerializer binarySerializerWithSmallBuffer = new GryoMessageSerializerV1d0();
+        final MessageSerializer<Kryo> binarySerializerWithSmallBuffer = new GryoMessageSerializerV1d0();
         final Map<String, Object> configWithSmallBuffer = new HashMap<String, Object>() {{
             // set to bufferSize < total message size but still greater than any individual object requires
             put("bufferSize", 50);
@@ -649,13 +649,13 @@
     }
 
     private ResponseMessage convertBinary(final Object toSerialize) throws SerializationException {
-        final MessageSerializer serializer = serializerSupplier.get();
+        final MessageSerializer<?> serializer = serializerSupplier.get();
         final ByteBuf bb = serializer.serializeResponseAsBinary(responseMessageBuilder.result(toSerialize).create(), allocator);
         return serializer.deserializeResponse(bb);
     }
 
     private ResponseMessage convertText(final Object toSerialize) throws SerializationException {
-        final MessageSerializer serializer = serializerSupplier.get();
+        final MessageSerializer<?> serializer = serializerSupplier.get();
         serializer.configure(configForText, null);
         final ByteBuf bb = serializer.serializeResponseAsBinary(responseMessageBuilder.result(toSerialize).create(), allocator);
         return serializer.deserializeResponse(bb);
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/binary/GraphBinaryMessageSerializerV1Test.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/binary/GraphBinaryMessageSerializerV1Test.java
index d0042ff..d77de48 100644
--- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/binary/GraphBinaryMessageSerializerV1Test.java
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/binary/GraphBinaryMessageSerializerV1Test.java
@@ -27,7 +27,6 @@
 import org.apache.tinkerpop.gremlin.driver.ser.SerializationException;
 import org.apache.tinkerpop.gremlin.structure.io.binary.TypeSerializerRegistry;
 import org.junit.Test;
-import org.mockito.internal.matchers.apachecommons.ReflectionEquals;
 
 import java.util.Collections;
 import java.util.HashMap;
@@ -35,8 +34,9 @@
 import java.util.UUID;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import static org.apache.tinkerpop.gremlin.driver.MockitoHamcrestMatcherAdapter.reflectionEquals;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 
 public class GraphBinaryMessageSerializerV1Test {
     private final ByteBufAllocator allocator = ByteBufAllocator.DEFAULT;
@@ -54,7 +54,7 @@
         final int mimeLen = buffer.readByte();
         buffer.readBytes(new byte[mimeLen]);
         final RequestMessage deserialized = serializer.deserializeRequest(buffer);
-        assertThat(request, new ReflectionEquals(deserialized));
+        assertThat(request, reflectionEquals(deserialized));
     }
 
     @Test
@@ -68,7 +68,7 @@
         final int mimeLen = buffer.readByte();
         buffer.readBytes(new byte[mimeLen]);
         final RequestMessage deserialized = serializer.deserializeRequest(buffer);
-        assertThat(request, new ReflectionEquals(deserialized));
+        assertThat(request, reflectionEquals(deserialized));
     }
 
     @Test
@@ -82,7 +82,7 @@
         final int mimeLen = buffer.readByte();
         buffer.readBytes(new byte[mimeLen]);
         final RequestMessage deserialized = serializer.deserializeRequest(buffer);
-        assertThat(request, new ReflectionEquals(deserialized));
+        assertThat(request, reflectionEquals(deserialized));
     }
 
     @Test
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/binary/GraphBinaryReaderWriterRoundTripTest.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/binary/GraphBinaryReaderWriterRoundTripTest.java
index ea7254d..5a351f1 100644
--- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/binary/GraphBinaryReaderWriterRoundTripTest.java
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/binary/GraphBinaryReaderWriterRoundTripTest.java
@@ -61,7 +61,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
-import org.mockito.internal.matchers.apachecommons.ReflectionEquals;
 
 import java.math.BigDecimal;
 import java.math.BigInteger;
@@ -86,9 +85,10 @@
 import java.util.concurrent.TimeUnit;
 import java.util.function.Consumer;
 
+import static org.apache.tinkerpop.gremlin.driver.MockitoHamcrestMatcherAdapter.reflectionEquals;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.hasLabel;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 
 @RunWith(Parameterized.class)
 public class GraphBinaryReaderWriterRoundTripTest {
@@ -265,19 +265,19 @@
                 new Object[] {"BulkSet", bulkSet, null},
                 new Object[] {"Tree", tree, null},
                 new Object[] {"EmptyMetrics", new MutableMetrics("idEmpty", "nameEmpty"), (Consumer<Metrics>) m -> {
-                    assertThat(m, new ReflectionEquals(new MutableMetrics("idEmpty", "nameEmpty")));
+                    assertThat(m, reflectionEquals(new MutableMetrics("idEmpty", "nameEmpty")));
                 }},
                 new Object[] {"Metrics", metrics, (Consumer<Metrics>) m -> {
-                    assertThat(m, new ReflectionEquals(metrics, "nested", "counts"));
+                    assertThat(m, reflectionEquals(metrics, "nested", "counts"));
                     assertEquals(new ArrayList(metrics.getCounts().values()), new ArrayList(m.getCounts().values()));
-                    assertThat(m.getNested(), new ReflectionEquals(metrics.getNested()));
+                    assertThat(m.getNested(), reflectionEquals(metrics.getNested()));
                 }},
                 new Object[] {"EmptyTraversalMetrics", emptyTraversalMetrics, (Consumer<TraversalMetrics>) m -> {
-                    assertThat(m, new ReflectionEquals(emptyTraversalMetrics));
+                    assertThat(m, reflectionEquals(emptyTraversalMetrics));
                 }},
                 new Object[] {"TraversalMetrics", traversalMetrics, (Consumer<TraversalMetrics>) m -> {
                     assertEquals(m.toString(), traversalMetrics.toString());
-                    assertThat(m, new ReflectionEquals(traversalMetrics, "stepIndexedMetrics", "positionIndexedMetrics"));
+                    assertThat(m, reflectionEquals(traversalMetrics, "stepIndexedMetrics", "positionIndexedMetrics"));
                 }},
 
                 // collections
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/binary/types/sample/SamplePersonSerializerTest.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/binary/types/sample/SamplePersonSerializerTest.java
index 1008653..7ff130e 100644
--- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/binary/types/sample/SamplePersonSerializerTest.java
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/binary/types/sample/SamplePersonSerializerTest.java
@@ -30,7 +30,6 @@
 import org.apache.tinkerpop.gremlin.structure.io.binary.GraphBinaryWriter;
 import org.apache.tinkerpop.gremlin.structure.io.binary.TypeSerializerRegistry;
 import org.junit.Test;
-import org.mockito.internal.matchers.apachecommons.ReflectionEquals;
 
 import java.io.IOException;
 import java.time.LocalDateTime;
@@ -41,9 +40,10 @@
 import java.util.Map;
 import java.util.UUID;
 
+import static org.apache.tinkerpop.gremlin.driver.MockitoHamcrestMatcherAdapter.reflectionEquals;
 import static org.apache.tinkerpop.gremlin.driver.ser.AbstractMessageSerializer.TOKEN_IO_REGISTRIES;
 import static org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1.TOKEN_CUSTOM;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 
 public class SamplePersonSerializerTest {
 
@@ -93,7 +93,7 @@
             writer.writeValue(person, buffer, nullable);
             final SamplePerson actual = reader.readValue(buffer, SamplePerson.class, nullable);
 
-            assertThat(actual, new ReflectionEquals(person));
+            assertThat(actual, reflectionEquals(person));
             buffer.release();
         }
     }
@@ -108,8 +108,7 @@
         final ResponseMessage deserialized = serializer.deserializeResponse(serialized);
 
         final SamplePerson actual = (SamplePerson) deserialized.getResult().getData();
-
-        assertThat(actual, new ReflectionEquals(person));
+        assertThat(actual, reflectionEquals(person));
     }
 
     public static class CustomIoRegistry extends AbstractIoRegistry {
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/util/Log4jRecordingAppenderTest.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/util/Log4jRecordingAppenderTest.java
index 7e3b0c8..05cb437 100644
--- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/util/Log4jRecordingAppenderTest.java
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/util/Log4jRecordingAppenderTest.java
@@ -27,7 +27,7 @@
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 
 /**
  * @author Stephen Mallette (http://stephen.genoprime.com)
diff --git a/gremlin-groovy/pom.xml b/gremlin-groovy/pom.xml
index f90b503..84effdc 100644
--- a/gremlin-groovy/pom.xml
+++ b/gremlin-groovy/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.apache.tinkerpop</groupId>
         <artifactId>tinkerpop</artifactId>
-        <version>3.4.12-SNAPSHOT</version>
+        <version>3.5.1-SNAPSHOT</version>
     </parent>
     <artifactId>gremlin-groovy</artifactId>
     <name>Apache TinkerPop :: Gremlin Groovy</name>
@@ -34,7 +34,7 @@
         <dependency>
             <groupId>org.apache.ivy</groupId>
             <artifactId>ivy</artifactId>
-            <version>2.3.0</version>
+            <version>2.4.0</version>
         </dependency>
         <dependency>
             <groupId>org.codehaus.groovy</groupId>
@@ -159,4 +159,29 @@
             </plugin>
         </plugins>
     </build>
+
+    <profiles>
+        <profile>
+            <id>jdk11</id>
+            <activation>
+                <jdk>11</jdk>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-javadoc-plugin</artifactId>
+                        <configuration>
+                            <!--
+                            need to override source path as we don't seem to get the groovy-stubs automatically. this worked
+                            under java 8 but errors under java 11 due to missing files on the path. i guess java 8 was more
+                            forgiving.
+                            -->
+                            <sourcepath>${pom.basedir}/src/main/java:${project.build.directory}/generated-sources/annotations:${project.build.directory}/generated-sources/groovy-stubs/main</sourcepath>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
 </project>
diff --git a/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/jsr223/ast/RepeatASTTransformationCustomizer.groovy b/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/jsr223/ast/RepeatASTTransformationCustomizer.groovy
new file mode 100644
index 0000000..e7d3107
--- /dev/null
+++ b/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/jsr223/ast/RepeatASTTransformationCustomizer.groovy
@@ -0,0 +1,51 @@
+package org.apache.tinkerpop.gremlin.groovy.jsr223.ast
+
+import groovy.transform.CompilationUnitAware
+import org.codehaus.groovy.ast.ASTNode
+import org.codehaus.groovy.ast.ClassNode
+import org.codehaus.groovy.classgen.GeneratorContext
+import org.codehaus.groovy.control.SourceUnit
+import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer
+import org.codehaus.groovy.transform.ASTTransformation
+
+/*
+ * 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.
+ */
+
+/**
+ * Overrides the single application of the specified global AST Transformation (which is how the base
+ * {@code ASTTransformationCustomizer} works. That approach is not so helpful in the ScriptEngine where we want
+ * each script to be treated as an independent source unit. This is a bit of a hack but the use case here is fairly
+ * narrow (i.e. {@code VarAsBindingASTTransformation})
+ */
+class RepeatASTTransformationCustomizer extends ASTTransformationCustomizer {
+    RepeatASTTransformationCustomizer(final ASTTransformation transformation) {
+        super(transformation)
+    }
+
+    @Override
+    @SuppressWarnings('Instanceof')
+    void call(SourceUnit source, GeneratorContext context, ClassNode classNode) {
+        if (transformation instanceof CompilationUnitAware) {
+            transformation.compilationUnit = compilationUnit
+        }
+
+        // this is a global AST transformation
+        transformation.visit(null, source)
+    }
+}
diff --git a/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/jsr223/ast/VarAsBindingASTTransformation.groovy b/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/jsr223/ast/VarAsBindingASTTransformation.groovy
new file mode 100644
index 0000000..5cee02b
--- /dev/null
+++ b/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/jsr223/ast/VarAsBindingASTTransformation.groovy
@@ -0,0 +1,141 @@
+/*
+ * 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.groovy.jsr223.ast
+
+import org.apache.tinkerpop.gremlin.process.traversal.Order
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__
+import org.apache.tinkerpop.gremlin.process.traversal.Translator
+import org.apache.tinkerpop.gremlin.process.traversal.Bytecode
+import org.apache.tinkerpop.gremlin.process.traversal.Bindings
+import org.codehaus.groovy.ast.ASTNode
+import org.codehaus.groovy.ast.ClassNode
+import org.codehaus.groovy.ast.CodeVisitorSupport
+import org.codehaus.groovy.ast.expr.ArgumentListExpression
+import org.codehaus.groovy.ast.expr.ClassExpression
+import org.codehaus.groovy.ast.expr.ConstantExpression
+import org.codehaus.groovy.ast.expr.DeclarationExpression
+import org.codehaus.groovy.ast.expr.Expression
+import org.codehaus.groovy.ast.expr.MethodCallExpression
+import org.codehaus.groovy.ast.expr.PropertyExpression
+import org.codehaus.groovy.ast.expr.StaticMethodCallExpression
+import org.codehaus.groovy.ast.expr.TupleExpression
+import org.codehaus.groovy.ast.expr.VariableExpression
+import org.codehaus.groovy.ast.stmt.ExpressionStatement
+import org.codehaus.groovy.control.CompilePhase
+import org.codehaus.groovy.control.SourceUnit
+import org.codehaus.groovy.syntax.Token
+import org.codehaus.groovy.syntax.Types
+import org.codehaus.groovy.transform.ASTTransformation
+import org.codehaus.groovy.transform.GroovyASTTransformation
+
+/**
+ * Converts variables used in Gremlin to {@link Bindings} declarations. By doing this, the generated traversal ends up
+ * having those {@link Bindings} in the Gremlin {@link Bytecode} which means that when passed through a
+ * {@link Translator} to generate a script form, the variables are preserved.
+ * <p/>
+ * This AST Transformation is meant to work with a single lines of Gremlin and only Gremlin. Inclusion of Groovy code
+ * might produce odd behavior as all variables found are basically treated as bindings which is not desirable for
+ * scripts in general.
+ * <p/>
+ * This class is meant for internal use only at this time as it has incomplete coverage over from the gherkin tests.
+ */
+@GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS)
+class VarAsBindingASTTransformation implements ASTTransformation {
+
+    private def bindingVariableName = 'bInDiNg' + UUID.randomUUID().toString().replace('-', '')
+
+    @Override
+    void visit(ASTNode[] nodes, SourceUnit source) {
+        // inject a binding declaration here using a unique variable name that should not interfere with variables
+        // in the Gremlin itself - basically generates the following line right before the Gremlin statement:
+        // bInDiNg<uuid> = Bindings.instance()
+        source.AST.statementBlock.statements.add(0, new ExpressionStatement(
+                new DeclarationExpression(
+                        new VariableExpression(bindingVariableName, new ClassNode(Bindings)),
+                        Token.newSymbol(Types.EQUAL, 0, 0),
+                        new StaticMethodCallExpression(new ClassNode(Bindings), "instance", new TupleExpression())
+                )
+        ))
+
+        // analyze the Gremlin and detect variables replacing them with:
+        // bInDiNg<uuid>.of(<var>,<some-default>)
+        source.AST.statementBlock.statements[1].visit(new CodeVisitorSupport() {
+
+            def currentMethod
+
+            @Override
+            void visitMethodCallExpression(MethodCallExpression call) {
+                currentMethod = call.methodAsString
+                call.getArguments().visit(this)
+                call.getObjectExpression().visit(this)
+            }
+
+            @Override
+            void visitArgumentlistExpression(ArgumentListExpression expression) {
+                if (!expression.empty) {
+                    expression.eachWithIndex{ Expression entry, int i ->
+                        if (entry instanceof VariableExpression) {
+                            // need a default binding value - any nonsense that satisfies the step argument should
+                            // work typically. the string default works for a great many cases, but sometimes we
+                            // need to get more specific. as it sits this list is incomplete and certain bindings
+                            // in certain position may generate errors still, but the entire set of gherkin files
+                            // passes with what is specified here currently. more tests will come as we build out
+                            // wider Gremlin coverage after the test suite is unified. as this body of code is
+                            // meant for testing only and it is documented as such it seems ok to leave this as-is
+                            // until we build out more Gherkin tests to expose any shortcomings.
+                            def bindingValue = new ConstantExpression(UUID.randomUUID().toString())
+                            switch (currentMethod) {
+                                case GraphTraversal.Symbols.map:
+                                case GraphTraversal.Symbols.filter:
+                                case GraphTraversal.Symbols.flatMap:
+                                case GraphTraversal.Symbols.sideEffect:
+                                case GraphTraversal.Symbols.choose:
+                                case GraphTraversal.Symbols.until:
+                                case GraphTraversal.Symbols.branch:
+                                    bindingValue = new StaticMethodCallExpression(new ClassNode(__), "identity", new TupleExpression())
+                                    break
+                                case GraphTraversal.Symbols.by:
+                                    if (i == 1) bindingValue = new PropertyExpression(new ClassExpression(new ClassNode(Order)), "desc")
+                                    break
+                            }
+                            def bindingExpression = createBindingFromVar(entry.text, bindingVariableName, bindingValue)
+                            bindingExpression.sourcePosition = entry
+                            bindingExpression.copyNodeMetaData(entry)
+                            expression.expressions[i] = bindingExpression
+                        }
+                    }
+                }
+                super.visitArgumentlistExpression(expression)
+            }
+        })
+    }
+
+    private static def createBindingFromVar(String nameOfVar, String bindingVariableName, Expression bindingValue) {
+        return new MethodCallExpression(
+                        new VariableExpression(bindingVariableName),
+                        new ConstantExpression("of"),
+                        new ArgumentListExpression(
+                                new ConstantExpression(nameOfVar),
+                                bindingValue
+                        )
+                )
+    }
+}
diff --git a/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/loaders/StepLoader.groovy b/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/loaders/StepLoader.groovy
index 974b8c1..f0c59e5 100644
--- a/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/loaders/StepLoader.groovy
+++ b/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/loaders/StepLoader.groovy
@@ -82,9 +82,9 @@
                     if (null == inst) throw new IllegalArgumentException("${it.name} missing a static 'instance()' method")
                     return inst
                 }
-            }
+            } as TraversalStrategy[]
 
-            return ((TraversalSource) delegate).withStrategies(*instances)
+            return ((TraversalSource) delegate).withStrategies(instances)
         }
     }
 }
diff --git a/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/loaders/StrategyLoader.groovy b/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/loaders/StrategyLoader.groovy
index b9651fd..15059af 100644
--- a/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/loaders/StrategyLoader.groovy
+++ b/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/loaders/StrategyLoader.groovy
@@ -18,12 +18,13 @@
  */
 package org.apache.tinkerpop.gremlin.groovy.loaders
 
-import org.apache.commons.configuration.MapConfiguration
+import org.apache.commons.configuration2.MapConfiguration
 import org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.ElementIdStrategy
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.HaltedTraverserStrategy
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.OptionsStrategy
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.PartitionStrategy
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SeedStrategy
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization.MatchAlgorithmStrategy
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.EdgeLabelVerificationStrategy
@@ -51,6 +52,7 @@
         PartitionStrategy.metaClass.constructor << { Map conf -> PartitionStrategy.create(new MapConfiguration(conf)) }
         // # RequirementsStrategy is internal
         // SackStrategy.metaClass.constructor << { Map conf -> SackStrategy.create(new MapConfiguration(conf)) }
+        SeedStrategy.metaClass.constructor << { Map conf -> SeedStrategy.create(new MapConfiguration(conf)) }
         // # SideEffectStrategy is internal
         SubgraphStrategy.metaClass.constructor << { Map conf -> SubgraphStrategy.create(new MapConfiguration(conf)) }
         VertexProgramStrategy.metaClass.constructor << { Map conf -> VertexProgramStrategy.create(new MapConfiguration(conf)) }
diff --git a/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutor.java b/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutor.java
index fe68ef9..ffef711 100644
--- a/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutor.java
+++ b/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutor.java
@@ -508,21 +508,6 @@
         }
 
         /**
-         * Amount of time a script has before it times out. Note that the time required covers both script evaluation
-         * as well as any time needed for a post result transformation (if the transformation function is supplied
-         * to the {@link GremlinExecutor#eval}).
-         *
-         * @param scriptEvaluationTimeout Time in milliseconds that an evaluation is allowed to run and its
-         *                                results potentially transformed. Set to zero to have no timeout set.
-         * @deprecated As of release 3.3.9, replaced by {@link #evaluationTimeout}.
-         */
-        @Deprecated
-        public Builder scriptEvaluationTimeout(final long scriptEvaluationTimeout) {
-            this.evaluationTimeout = scriptEvaluationTimeout;
-            return this;
-        }
-
-        /**
          * Amount of time an evaluation has before it times out. Note that the time required covers both evaluation
          * as well as any time needed for a post result transformation (if the transformation function is supplied
          * to the {@link GremlinExecutor#eval}).
@@ -639,14 +624,6 @@
             evaluationTimeoutOverride = Optional.ofNullable(builder.evaluationTimeoutOverride);
         }
 
-        /**
-         * @deprecated As of release 3.3.9, replaced by {@link #getEvaluationTimeoutOverride()}.
-         */
-        @Deprecated
-        public Optional<Long> getScriptEvaluationTimeoutOverride() {
-            return evaluationTimeoutOverride;
-        }
-
         public Optional<Long> getEvaluationTimeoutOverride() {
             return evaluationTimeoutOverride;
         }
@@ -746,18 +723,6 @@
             /**
              * An override to the global {@code evaluationTimeout} setting on the script engine. If this value
              * is set to {@code null} (the default) it will use the global setting.
-             *
-             * @deprecated As of release 3.3.9, replaced by {@link #evaluationTimeoutOverride}
-             */
-            @Deprecated
-            public Builder scriptEvaluationTimeoutOverride(final Long scriptEvaluationTimeoutOverride) {
-                this.evaluationTimeoutOverride = scriptEvaluationTimeoutOverride;
-                return this;
-            }
-
-            /**
-             * An override to the global {@code evaluationTimeout} setting on the script engine. If this value
-             * is set to {@code null} (the default) it will use the global setting.
              */
             public Builder evaluationTimeoutOverride(final Long evaluationTimeoutOverride) {
                 this.evaluationTimeoutOverride = evaluationTimeoutOverride;
diff --git a/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngine.java b/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngine.java
index 3281fb2..df9a85a 100644
--- a/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngine.java
+++ b/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngine.java
@@ -215,10 +215,11 @@
         // initialize the global scope in case this scriptengine was instantiated outside of the ScriptEngineManager
         setBindings(new ConcurrentBindings(), ScriptContext.GLOBAL_SCOPE);
 
-        final List<Customizer> listOfCustomizers = new ArrayList<>(Arrays.asList(customizers));
+        final List<Customizer> listOfCustomizers = new ArrayList<>();
 
         // always need this plugin for a scriptengine to be "Gremlin-enabled"
         CoreGremlinPlugin.instance().getCustomizers("gremlin-groovy").ifPresent(c -> listOfCustomizers.addAll(Arrays.asList(c)));
+        listOfCustomizers.addAll(Arrays.asList(customizers));
 
         GremlinLoader.load();
 
@@ -258,7 +259,7 @@
                 filter(p -> p instanceof TranslatorCustomizer).
                 map(p -> (TranslatorCustomizer) p).findFirst();
         typeTranslator = translatorCustomizer.map(TranslatorCustomizer::createTypeTranslator).
-                orElseGet(org.apache.tinkerpop.gremlin.process.traversal.translator.GroovyTranslator.DefaultTypeTranslator::new);
+                orElseGet(() -> new org.apache.tinkerpop.gremlin.process.traversal.translator.GroovyTranslator.DefaultTypeTranslator(false));
 
         createClassLoader();
     }
@@ -292,8 +293,9 @@
         inner.putAll(bindings);
         inner.putAll(bytecode.getBindings());
         inner.put(HIDDEN_G, b);
-
-        return (Traversal.Admin) this.eval(org.apache.tinkerpop.gremlin.process.traversal.translator.GroovyTranslator.of(HIDDEN_G, typeTranslator).translate(bytecode), inner);
+        org.apache.tinkerpop.gremlin.process.traversal.Script script = org.apache.tinkerpop.gremlin.process.traversal.translator.GroovyTranslator.of(HIDDEN_G, typeTranslator).translate(bytecode);
+        script.getParameters().ifPresent(inner::putAll);
+        return (Traversal.Admin) this.eval(script.getScript(), inner);
     }
 
     /**
@@ -371,7 +373,7 @@
 
         try {
             registerBindingTypes(context);
-            final Class clazz = getScriptClass(script);
+            final Class<?> clazz = getScriptClass(script);
             if (null == clazz) throw new ScriptException("Script class is null");
             return eval(clazz, context);
         } catch (Exception e) {
diff --git a/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslator.java b/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslator.java
index ec439fa..f7f773e 100644
--- a/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslator.java
+++ b/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslator.java
@@ -20,10 +20,11 @@
 package org.apache.tinkerpop.gremlin.groovy.jsr223;
 
 import groovy.json.StringEscapeUtils;
-import org.apache.commons.configuration.ConfigurationConverter;
+import org.apache.commons.configuration2.ConfigurationConverter;
 import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
 import org.apache.tinkerpop.gremlin.process.traversal.P;
 import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
+import org.apache.tinkerpop.gremlin.process.traversal.Script;
 import org.apache.tinkerpop.gremlin.process.traversal.TextP;
 import org.apache.tinkerpop.gremlin.process.traversal.Translator;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
@@ -41,14 +42,13 @@
 import org.apache.tinkerpop.gremlin.util.function.Lambda;
 
 import java.sql.Timestamp;
-import java.util.ArrayList;
 import java.util.Date;
-import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Optional;
 import java.util.Set;
 import java.util.UUID;
+import java.util.stream.Collectors;
 import java.util.function.BinaryOperator;
 import java.util.function.Supplier;
 import java.util.function.UnaryOperator;
@@ -58,6 +58,7 @@
  *
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  * @author Stephen Mallette (http://stephen.genoprime.com)
+ * @author Stark Arya (sandszhou.zj@alibaba-inc.com)
  * @deprecated As of release 3.4.9, moved to {@link org.apache.tinkerpop.gremlin.process.traversal.translator.GroovyTranslator} in {@code gremlin-core}.
  */
 @Deprecated
@@ -71,20 +72,32 @@
         this.typeTranslator = typeTranslator;
     }
 
+    /**
+     * Creates the translator with a {@code false} argument to {@code withParameters} using
+     * {@link #of(String, boolean)}.
+     */
     public static final GroovyTranslator of(final String traversalSource) {
-        return of(traversalSource, null);
+        return of(traversalSource, false);
+    }
+
+    /**
+     * Creates the translator with the {@link DefaultTypeTranslator} passing the {@code withParameters} option to it
+     * which will handle type translation in a fashion that should typically increase cache hits and reduce
+     * compilation times if enabled at the sacrifice to rewriting of the script that could reduce readability.
+     */
+    public static final GroovyTranslator of(final String traversalSource, final boolean withParameters) {
+        return of(traversalSource, new DefaultTypeTranslator(withParameters));
     }
 
     public static final GroovyTranslator of(final String traversalSource, final TypeTranslator typeTranslator) {
-        return new GroovyTranslator(traversalSource,
-                Optional.ofNullable(typeTranslator).orElseGet(DefaultTypeTranslator::new));
+        return new GroovyTranslator(traversalSource, typeTranslator);
     }
 
     ///////
 
     @Override
-    public String translate(final Bytecode bytecode) {
-        return typeTranslator.apply(traversalSource, bytecode).toString();
+    public Script translate(final Bytecode bytecode) {
+        return typeTranslator.apply(traversalSource, bytecode);
     }
 
     @Override
@@ -106,127 +119,198 @@
      * Performs standard type translation for the TinkerPop types to Groovy.
      */
     public static class DefaultTypeTranslator implements TypeTranslator {
+        protected final boolean withParameters;
+        protected final Script script;
 
-        @Override
-        public Object apply(final String traversalSource, final Object o) {
-            if (o instanceof Bytecode)
-                return internalTranslate(traversalSource, (Bytecode) o);
-            else
-                return convertToString(o);
+        public DefaultTypeTranslator(final boolean withParameters) {
+           this.withParameters = withParameters;
+           this.script = new Script();
         }
 
-        protected String convertToString(final Object object) {
-            if (object instanceof Bytecode.Binding)
-                return ((Bytecode.Binding) object).variable();
-            else if (object instanceof Bytecode)
+        @Override
+        public Script apply(final String traversalSource, final Object o) {
+            this.script.init();
+            if (o instanceof Bytecode) {
+                return internalTranslate(traversalSource, (Bytecode) o);
+            } else {
+                return convertToScript(o);
+            }
+        }
+
+        /**
+         *  For each operator argument, if withParameters set true, try parametrization as follows:
+         *
+         *  -----------------------------------------------
+         *  if unpack, why ?      ObjectType
+         *  -----------------------------------------------
+         *  (Yes)                 Bytecode.Binding
+         *  (Recursion, No)       Bytecode
+         *  (Recursion, No)       Traversal
+         *  (Yes)                 String
+         *  (Recursion, No)       Set
+         *  (Recursion, No)       List
+         *  (Recursion, No)       Map
+         *  (Yes)                 Long
+         *  (Yes)                 Double
+         *  (Yes)                 Float
+         *  (Yes)                 Integer
+         *  (Yes)                 Timestamp
+         *  (Yes)                 Date
+         *  (Yes)                 Uuid
+         *  (Recursion, No)       P
+         *  (Enumeration, No)     SackFunctions.Barrier
+         *  (Enumeration, No)     VertexProperty.Cardinality
+         *  (Enumeration, No)     TraversalOptionParent.Pick
+         *  (Enumeration, No)     Enum
+         *  (Recursion, No)       Vertex
+         *  (Recursion, No)       Edge
+         *  (Recursion, No)       VertexProperty
+         *  (Yes)                 Lambda
+         *  (Recursion, No)       TraversalStrategyProxy
+         *  (Enumeration, No)     TraversalStrategy
+         *  (Yes)                 Other
+         *  -------------------------------------------------
+         *
+         * @param object
+         * @return String Repres
+         */
+        protected Script convertToScript(final Object object) {
+            if (object instanceof Bytecode.Binding) {
+                return script.getBoundKeyOrAssign(withParameters, ((Bytecode.Binding) object).variable());
+            } else if (object instanceof Bytecode) {
                 return internalTranslate("__", (Bytecode) object);
-            else if (object instanceof Traversal)
-                return convertToString(((Traversal) object).asAdmin().getBytecode());
-            else if (object instanceof String) {
-                return (((String) object).contains("\"") ? "\"\"\"" + StringEscapeUtils.escapeJava((String) object) + "\"\"\"" : "\"" + StringEscapeUtils.escapeJava((String) object) + "\"")
+            } else if (object instanceof Traversal) {
+                return convertToScript(((Traversal) object).asAdmin().getBytecode());
+            } else if (object instanceof String) {
+                final String wrapper = (((String) object).contains("\"") ? "\"\"\"" + StringEscapeUtils.escapeJava((String) object) + "\"\"\"" : "\"" + StringEscapeUtils.escapeJava((String) object) + "\"")
                         .replace("$", "\\$");
+                return script.getBoundKeyOrAssign(withParameters, withParameters ? object : wrapper);
             } else if (object instanceof Set) {
-                final Set<String> set = new HashSet<>(((Set) object).size());
-                for (final Object item : (Set) object) {
-                    set.add(convertToString(item));
-                }
-                return set.toString() + " as Set";
+                convertToScript(((Set)object).stream().collect(Collectors.toList()));
+                return script.append(" as Set");
             } else if (object instanceof List) {
-                final List<String> list = new ArrayList<>(((List) object).size());
-                for (final Object item : (List) object) {
-                    list.add(convertToString(item));
+                Iterator<?> iterator = ((List)object).iterator();
+                if (! iterator.hasNext()) {
+                    return script.append("[]");
+                } else {
+                    script.append("[");
+                    for (;;)  {
+                        Object e =  iterator.next();
+                        convertToScript(e);
+                        if (! iterator.hasNext()) {
+                            return script.append("]");
+                        } else {
+                            script.append(",").append(" ");
+                        }
+                    }
                 }
-                return list.toString();
             } else if (object instanceof Map) {
-                final StringBuilder map = new StringBuilder("[");
+                script.append("[");
                 for (final Map.Entry<?, ?> entry : ((Map<?, ?>) object).entrySet()) {
-                    map.append("(").
-                            append(convertToString(entry.getKey())).
-                            append("):(").
-                            append(convertToString(entry.getValue())).
-                            append("),");
+                    script.append("(");
+                    convertToScript(entry.getKey());
+                    script.append("):(");
+                    convertToScript(entry.getValue());
+                    script.append("),");
                 }
 
                 // only need to remove this last bit if entries were added
-                if (!((Map<?, ?>) object).isEmpty())
-                    map.deleteCharAt(map.length() - 1);
-
-                return map.append("]").toString();
-            } else if (object instanceof Long)
-                return object + "L";
-            else if (object instanceof Double)
-                return object + "d";
-            else if (object instanceof Float)
-                return object + "f";
-            else if (object instanceof Integer)
-                return "(int) " + object;
-            else if (object instanceof Class)
-                return ((Class) object).getCanonicalName();
-            else if (object instanceof Timestamp)
-                return "new java.sql.Timestamp(" + ((Timestamp) object).getTime() + ")";
-            else if (object instanceof Date)
-                return "new java.util.Date(" + ((Date) object).getTime() + ")";
-            else if (object instanceof UUID)
-                return "java.util.UUID.fromString('" + object.toString() + "')";
-            else if (object instanceof P)
-                return convertPToString((P) object, new StringBuilder()).toString();
-            else if (object instanceof SackFunctions.Barrier)
-                return "SackFunctions.Barrier." + object.toString();
-            else if (object instanceof VertexProperty.Cardinality)
-                return "VertexProperty.Cardinality." + object.toString();
-            else if (object instanceof TraversalOptionParent.Pick)
-                return "TraversalOptionParent.Pick." + object.toString();
-            else if (object instanceof Enum)
-                return ((Enum) object).getDeclaringClass().getSimpleName() + "." + object.toString();
-            else if (object instanceof Element) {
+                if (!((Map<?, ?>) object).isEmpty()) {
+                    return script.setCharAtEnd(']');
+                } else {
+                    return script.append("]");
+                }
+            } else if (object instanceof Long) {
+                return script.getBoundKeyOrAssign(withParameters, withParameters ? object : object + "L");
+            } else if (object instanceof Double) {
+                return script.getBoundKeyOrAssign(withParameters, withParameters ? object : object + "d");
+            } else if (object instanceof Float) {
+                return script.getBoundKeyOrAssign(withParameters, withParameters ? object : object + "f");
+            } else if (object instanceof Integer) {
+                return script.getBoundKeyOrAssign(withParameters, withParameters ? object : "(int) " + object);
+            } else if (object instanceof Class) {
+                return script.append(((Class) object).getCanonicalName());
+            } else if (object instanceof Timestamp) {
+                return script.getBoundKeyOrAssign(withParameters, withParameters ? object : "new java.sql.Timestamp(" + ((Timestamp) object).getTime() + ")");
+            } else if (object instanceof Date) {
+                return script.getBoundKeyOrAssign(withParameters, withParameters ? object : "new java.util.Date(" + ((Date) object).getTime() + ")");
+            } else if (object instanceof UUID) {
+                return script.getBoundKeyOrAssign(withParameters, withParameters ? object : "java.util.UUID.fromString('" + object.toString() + "')");
+            } else if (object instanceof P) {
+                return convertPToScript((P) object);
+            } else if (object instanceof SackFunctions.Barrier) {
+                return script.append("SackFunctions.Barrier." + object.toString());
+            } else if (object instanceof VertexProperty.Cardinality) {
+                return script.append("VertexProperty.Cardinality." + object.toString());
+            } else if (object instanceof TraversalOptionParent.Pick) {
+                return script.append("TraversalOptionParent.Pick." + object.toString());
+            } else if (object instanceof Enum) {
+                return script.append(((Enum) object).getDeclaringClass().getSimpleName() + "." + object.toString());
+            } else if (object instanceof Element) {
                 if (object instanceof Vertex) {
                     final Vertex vertex = (Vertex) object;
-                    return "new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex(" +
-                            convertToString(vertex.id()) + "," +
-                            convertToString(vertex.label()) + ", Collections.emptyMap())";
+                    script.append("new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex(");
+                    convertToScript(vertex.id());
+                    script.append(",");
+                    convertToScript(vertex.label());
+                    return script.append(", Collections.emptyMap())");
                 } else if (object instanceof Edge) {
                     final Edge edge = (Edge) object;
-                    return "new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedEdge(" +
-                            convertToString(edge.id()) + "," +
-                            convertToString(edge.label()) + "," +
-                            "Collections.emptyMap()," +
-                            convertToString(edge.outVertex().id()) + "," +
-                            convertToString(edge.outVertex().label()) + "," +
-                            convertToString(edge.inVertex().id()) + "," +
-                            convertToString(edge.inVertex().label()) + ")";
+                    script.append("new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedEdge(");
+                    convertToScript(edge.id());
+                    script.append(",");
+                    convertToScript(edge.label());
+                    script.append(",");
+                    script.append("Collections.emptyMap(),");
+                    convertToScript(edge.outVertex().id());
+                    script.append(",");
+                    convertToScript(edge.outVertex().label());
+                    script.append(",");
+                    convertToScript(edge.inVertex().id());
+                    script.append(",");
+                    convertToScript(edge.inVertex().label());
+                    return script.append(")");
                 } else {// VertexProperty
                     final VertexProperty vertexProperty = (VertexProperty) object;
-                    return "new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertexProperty(" +
-                            convertToString(vertexProperty.id()) + "," +
-                            convertToString(vertexProperty.label()) + "," +
-                            convertToString(vertexProperty.value()) + "," +
-                            "Collections.emptyMap()," +
-                            convertToString(vertexProperty.element()) + ")";
+                    script.append("new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertexProperty(");
+                    convertToScript(vertexProperty.id());
+                    script.append(",");
+                    convertToScript(vertexProperty.label());
+                    script.append(",");
+                    convertToScript(vertexProperty.value());
+                    script.append(",");
+                    script.append("Collections.emptyMap(),");
+                    convertToScript(vertexProperty.element());
+                    return script.append(")");
                 }
             } else if (object instanceof Lambda) {
                 final String lambdaString = ((Lambda) object).getLambdaScript().trim();
-                return lambdaString.startsWith("{") ? lambdaString : "{" + lambdaString + "}";
+                final String wrapper = lambdaString.startsWith("{") ? lambdaString : "{" + lambdaString + "}";
+                return script.getBoundKeyOrAssign(withParameters, withParameters ? object : wrapper);
             } else if (object instanceof TraversalStrategyProxy) {
                 final TraversalStrategyProxy proxy = (TraversalStrategyProxy) object;
-                if (proxy.getConfiguration().isEmpty())
-                    return proxy.getStrategyClass().getCanonicalName() + ".instance()";
-                else
-                    return proxy.getStrategyClass().getCanonicalName() + ".create(new org.apache.commons.configuration.MapConfiguration(" + convertToString(ConfigurationConverter.getMap(proxy.getConfiguration())) + "))";
+                if (proxy.getConfiguration().isEmpty()) {
+                    return script.append(proxy.getStrategyClass().getCanonicalName() + ".instance()");
+                } else {
+                    script.append(proxy.getStrategyClass().getCanonicalName() + ".create(new org.apache.commons.configuration2.MapConfiguration(");
+                    convertToScript(ConfigurationConverter.getMap(proxy.getConfiguration()));
+                    return script.append("))");
+                }
             } else if (object instanceof TraversalStrategy) {
-                return convertToString(new TraversalStrategyProxy(((TraversalStrategy) object)));
-            } else
-                return null == object ? "null" : object.toString();
+                return convertToScript(new TraversalStrategyProxy(((TraversalStrategy) object)));
+            } else {
+                return null == object ? script.append("null") : script.getBoundKeyOrAssign(withParameters, object);
+            }
         }
 
-        protected String internalTranslate(final String start, final Bytecode bytecode) {
-            final StringBuilder traversalScript = new StringBuilder(start);
+        protected Script internalTranslate(final String start, final Bytecode bytecode) {
+            script.append(start);
             for (final Bytecode.Instruction instruction : bytecode.getInstructions()) {
                 final String methodName = instruction.getOperator();
-                if (0 == instruction.getArguments().length)
-                    traversalScript.append(".").append(methodName).append("()");
-                else {
-                    traversalScript.append(".");
-                    String temp = methodName + "(";
+                if (0 == instruction.getArguments().length) {
+                    script.append(".").append(methodName).append("()");
+                } else {
+                    script.append(".").append(methodName).append("(");
 
                     // have to special case withSack() for Groovy because UnaryOperator and BinaryOperator signatures
                     // make it impossible for the interpreter to figure out which function to call. specifically we need
@@ -244,39 +328,49 @@
                         final String castSecondArgTo = secondArg.getLambdaArguments() == 1 ? UnaryOperator.class.getName() :
                                 BinaryOperator.class.getName();
                         if (!castFirstArgTo.isEmpty())
-                            temp = temp + String.format("(%s) ", castFirstArgTo);
-                        temp = temp + String.format("%s, (%s) %s,",
-                                convertToString(instruction.getArguments()[0]), castSecondArgTo,
-                                convertToString(instruction.getArguments()[1]));
+                            script.append(String.format("(%s) ", castFirstArgTo));
+                        convertToScript(instruction.getArguments()[0]);
+                        script.append(", (").append(castSecondArgTo).append(") ");
+                        convertToScript(instruction.getArguments()[1]);
+                        script.append(",");
                     } else {
                         for (final Object object : instruction.getArguments()) {
-                            temp = temp + convertToString(object) + ",";
+                            convertToScript(object);
+                            script.append(",");
                         }
                     }
-                    traversalScript.append(temp.substring(0, temp.length() - 1)).append(")");
+                    script.setCharAtEnd(')');
                 }
             }
-            return traversalScript.toString();
+            return script;
         }
 
-        protected StringBuilder convertPToString(final P p, final StringBuilder current) {
-            if (p instanceof TextP) return convertTextPToString((TextP) p, current);
+        protected Script convertPToScript(final P p) {
+            if (p instanceof TextP) {
+                return convertTextPToScript((TextP) p);
+            }
             if (p instanceof ConnectiveP) {
                 final List<P<?>> list = ((ConnectiveP) p).getPredicates();
                 for (int i = 0; i < list.size(); i++) {
-                    convertPToString(list.get(i), current);
-                    if (i < list.size() - 1)
-                        current.append(p instanceof OrP ? ".or(" : ".and(");
+                    convertPToScript(list.get(i));
+                    if (i < list.size() - 1) {
+                        script.append(p instanceof OrP ? ".or(" : ".and(");
+                    }
                 }
-                current.append(")");
-            } else
-                current.append("P.").append(p.getBiPredicate().toString()).append("(").append(convertToString(p.getValue())).append(")");
-            return current;
+                script.append(")");
+            } else {
+                script.append("P.").append(p.getBiPredicate().toString()).append("(");
+                convertToScript(p.getValue());
+                script.append(")");
+            }
+            return script;
         }
 
-        protected StringBuilder convertTextPToString(final TextP p, final StringBuilder current) {
-            current.append("TextP.").append(p.getBiPredicate().toString()).append("(").append(convertToString(p.getValue())).append(")");
-            return current;
+        protected Script convertTextPToScript(final TextP p) {
+            script.append("TextP.").append(p.getBiPredicate().toString()).append("(");
+            convertToScript(p.getValue());
+            script.append(")");
+            return script;
         }
     }
 }
diff --git a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorOverGraphTest.java b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorOverGraphTest.java
index 3e0ad87..4b8e113 100644
--- a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorOverGraphTest.java
+++ b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorOverGraphTest.java
@@ -38,7 +38,7 @@
 
 import static org.hamcrest.core.StringStartsWith.startsWith;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.fail;
 
 /**
diff --git a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorTest.java b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorTest.java
index 226a3f7..50e1aec 100644
--- a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorTest.java
+++ b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorTest.java
@@ -267,7 +267,7 @@
         final CountDownLatch timeOutCount = new CountDownLatch(1);
 
         final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
-                .scriptEvaluationTimeout(250)
+                .evaluationTimeout(250)
                 .afterFailure((b, e) -> failureCalled.set(true))
                 .afterSuccess((b) -> successCalled.set(true))
                 .afterTimeout((b) -> timeOutCount.countDown()).create();
@@ -321,13 +321,13 @@
         final CountDownLatch timeOutCount = new CountDownLatch(1);
 
         final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
-                .scriptEvaluationTimeout(10000)
+                .evaluationTimeout(10000)
                 .afterFailure((b, e) -> failureCalled.set(true))
                 .afterSuccess((b) -> successCalled.set(true))
                 .afterTimeout((b) -> timeOutCount.countDown()).create();
         try {
             final GremlinExecutor.LifeCycle lifeCycle = GremlinExecutor.LifeCycle.build()
-                    .scriptEvaluationTimeoutOverride(250L).create();
+                    .evaluationTimeoutOverride(250L).create();
             gremlinExecutor.eval("Thread.sleep(1000);10", "gremlin-groovy", new SimpleBindings(), lifeCycle).get();
             fail("This script should have timed out with an exception");
         } catch (Exception ex) {
@@ -460,15 +460,15 @@
 
     @Test
     public void shouldCancelTimeoutOnSuccessfulScript() throws Exception {
-        final long scriptEvaluationTimeout = 5_000;
+        final long evaluationTimeout = 5_000;
         final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
-                .scriptEvaluationTimeout(scriptEvaluationTimeout)
+                .evaluationTimeout(evaluationTimeout)
                 .create();
 
         final long now = System.currentTimeMillis();
         assertEquals(2, gremlinExecutor.eval("1+1").get());
         gremlinExecutor.close();
-        assertTrue(System.currentTimeMillis() - now < scriptEvaluationTimeout);
+        assertTrue(System.currentTimeMillis() - now < evaluationTimeout);
     }
 
     @Test
diff --git a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineCompileStaticTest.java b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineCompileStaticTest.java
index bceefd8..fcfe61f 100644
--- a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineCompileStaticTest.java
+++ b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineCompileStaticTest.java
@@ -26,7 +26,7 @@
 
 import static org.hamcrest.Matchers.containsString;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.fail;
 
 /**
diff --git a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineFileSandboxTest.java b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineFileSandboxTest.java
index 2a094e2..81ae9ad 100644
--- a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineFileSandboxTest.java
+++ b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineFileSandboxTest.java
@@ -40,7 +40,7 @@
 import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.greaterThan;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.fail;
 
 /**
diff --git a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineSandboxedStandardTest.java b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineSandboxedStandardTest.java
index b203ba8..31aad1f 100644
--- a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineSandboxedStandardTest.java
+++ b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineSandboxedStandardTest.java
@@ -33,7 +33,7 @@
 
 import static org.hamcrest.Matchers.containsString;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.fail;
 
 /**
diff --git a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTest.java b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTest.java
index efb6812..5461c74 100644
--- a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTest.java
+++ b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTest.java
@@ -23,14 +23,20 @@
 import groovy.lang.MissingPropertyException;
 import org.apache.commons.lang3.exception.ExceptionUtils;
 import org.apache.commons.lang3.concurrent.BasicThreadFactory;
+import org.apache.tinkerpop.gremlin.groovy.jsr223.ast.RepeatASTTransformationCustomizer;
+import org.apache.tinkerpop.gremlin.groovy.jsr223.ast.VarAsBindingASTTransformation;
+import org.apache.tinkerpop.gremlin.jsr223.DefaultImportCustomizer;
+import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
 import org.apache.tinkerpop.gremlin.process.traversal.step.filter.HasStep;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy;
-import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.VerificationException;
+import org.apache.tinkerpop.gremlin.process.traversal.translator.PythonTranslator;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
 import org.apache.tinkerpop.gremlin.util.function.Lambda;
+import org.codehaus.groovy.control.customizers.CompilationCustomizer;
 import org.javatuples.Pair;
 import org.junit.Test;
 
@@ -52,7 +58,7 @@
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.stream.IntStream;
 
-import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.hasLabel;
+import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.core.Is.is;
 import static org.hamcrest.core.IsInstanceOf.instanceOf;
@@ -449,4 +455,58 @@
         assertThat(ss.isPresent(), is(true));
         assertEquals(HasStep.class, ss.get().getVertexCriterion().asAdmin().getStartStep().getClass());
     }
+
+    /**
+     * Test for TINKERPOP-2394 Unable to use __ class of a custom DSL when passing a script even if this class is imported
+     */
+	@Test
+	public void customizerShouldOverrideCoreImports() throws Exception {
+		DefaultImportCustomizer customizer = DefaultImportCustomizer.build()
+				.addClassImports(org.apache.tinkerpop.gremlin.groovy.jsr223.dsl.credential.__.class)
+				.create();
+		final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine(customizer);
+		engine.eval("__.users();[]");
+	}
+
+    @Test
+    public void shouldProduceBindingsForVars() throws Exception {
+        final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine(new GroovyCustomizer() {
+            @Override
+            public CompilationCustomizer create() {
+                return new RepeatASTTransformationCustomizer(new VarAsBindingASTTransformation());
+            }
+        });
+
+        final GraphTraversalSource g = traversal().withEmbedded(EmptyGraph.instance());
+        final Bindings bindings = new SimpleBindings();
+        bindings.put("g", g);
+        engine.eval("g.V(b).out()", bindings);
+        final Traversal.Admin<Vertex, Vertex> t = (Traversal.Admin<Vertex, Vertex>)
+                engine.eval("g.V(v1Id).has(\"person\",\"age\",29).has('person','active',x).in(\"knows\")." +
+                        System.lineSeparator() +
+                        "choose(__.out().count()).option(two, __.values(\"name\")).option(three, __.values(\"age\"))." +
+                        System.lineSeparator() +
+                        "filter(outE().count().is(y))."  +
+                        System.lineSeparator() +
+                        "map(l)." +
+                        System.lineSeparator() +
+                        "order().by('name',o)", bindings);
+        final Bytecode bytecode = t.getBytecode();
+        engine.eval("g.V(b).out()", bindings);
+
+        final PythonTranslator translator = PythonTranslator.of("g");
+        final String gremlinAsPython = translator.translate(bytecode).getScript();
+
+        final Map<String,Object> bytecodeBindings = bytecode.getBindings();
+        assertEquals(7, bytecodeBindings.size());
+        assertThat(bytecodeBindings.containsKey("x"), is(true));
+        assertThat(bytecodeBindings.containsKey("y"), is(true));
+        assertThat(bytecodeBindings.containsKey("v1Id"), is(true));
+        assertThat(bytecodeBindings.containsKey("l"), is(true));
+        assertThat(bytecodeBindings.containsKey("o"), is(true));
+        assertThat(bytecodeBindings.containsKey("two"), is(true));
+        assertThat(bytecodeBindings.containsKey("three"), is(true));
+
+        assertEquals("g.V(v1Id).has('person','age',29).has('person','active',x).in_('knows').choose(__.out().count()).option(two,__.name).option(three,__.age).filter(__.outE().count().is_(y)).map(l).order().by('name',o)", gremlinAsPython);
+    }
 }
\ No newline at end of file
diff --git a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTinkerPopSandboxTest.java b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTinkerPopSandboxTest.java
index fd36eaa..d1a1091 100644
--- a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTinkerPopSandboxTest.java
+++ b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTinkerPopSandboxTest.java
@@ -30,7 +30,7 @@
 
 import static org.hamcrest.Matchers.containsString;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.fail;
 
 /**
diff --git a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTypeCheckedTest.java b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTypeCheckedTest.java
index d41f07d..098703f 100644
--- a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTypeCheckedTest.java
+++ b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTypeCheckedTest.java
@@ -26,7 +26,7 @@
 
 import static org.hamcrest.Matchers.containsString;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.fail;
 
 /**
diff --git a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslatorProvider.java b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslatorProvider.java
index de01349..c44f35c 100644
--- a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslatorProvider.java
+++ b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslatorProvider.java
@@ -208,10 +208,6 @@
         method = "shouldNeverPropagateANoBulkTraverser",
         reason = "Reason requires investigation")
 @Graph.OptOut(
-        test = "org.apache.tinkerpop.gremlin.process.traversal.CoreTraversalTest",
-        method = "shouldNeverPropagateANullValuedTraverser",
-        reason = "Reason requires investigation")
-@Graph.OptOut(
         test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.ReadTest",
         method = "*",
         reason = "read and write tests don't translate locally well because of calling iterate() inside read()/write() add a none()")
diff --git a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslatorTest.java b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslatorTest.java
index 71f79ec..eda6ba8 100644
--- a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslatorTest.java
+++ b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslatorTest.java
@@ -19,11 +19,12 @@
 
 package org.apache.tinkerpop.gremlin.groovy.jsr223;
 
-import org.apache.commons.configuration.MapConfiguration;
+import org.apache.commons.configuration2.MapConfiguration;
 import org.apache.tinkerpop.gremlin.jsr223.TranslatorCustomizer;
 import org.apache.tinkerpop.gremlin.process.traversal.Order;
 import org.apache.tinkerpop.gremlin.process.traversal.Pop;
 import org.apache.tinkerpop.gremlin.process.traversal.Scope;
+import org.apache.tinkerpop.gremlin.process.traversal.Script;
 import org.apache.tinkerpop.gremlin.process.traversal.Translator;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
@@ -65,7 +66,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.fail;
 
 /**
@@ -107,22 +108,22 @@
         final GraphTraversalSource g = graph.traversal();
 
         final Traversal<Vertex,Double> tConstantUnary = g.withSack(1.0, Lambda.unaryOperator("it + 1")).V().sack();
-        final String scriptConstantUnary = GroovyTranslator.of("g").translate(tConstantUnary.asAdmin().getBytecode());
+        final String scriptConstantUnary = GroovyTranslator.of("g").translate(tConstantUnary.asAdmin().getBytecode()).getScript();
         assertEquals("g.withSack(1.0d, (java.util.function.UnaryOperator) {it + 1}).V().sack()", scriptConstantUnary);
         assertThatScriptOk(scriptConstantUnary, "g", g);
 
         final Traversal<Vertex,Double> tSupplierUnary = g.withSack(Lambda.supplier("1.0d"), Lambda.<Double>unaryOperator("it + 1")).V().sack();
-        final String scriptSupplierUnary = GroovyTranslator.of("g").translate(tSupplierUnary.asAdmin().getBytecode());
+        final String scriptSupplierUnary = GroovyTranslator.of("g").translate(tSupplierUnary.asAdmin().getBytecode()).getScript();
         assertEquals("g.withSack((java.util.function.Supplier) {1.0d}, (java.util.function.UnaryOperator) {it + 1}).V().sack()", scriptSupplierUnary);
         assertThatScriptOk(scriptSupplierUnary, "g", g);
 
         final Traversal<Vertex,Double> tConstantBinary = g.withSack(1.0, Lambda.binaryOperator("x,y -> x + y + 1")).V().sack();
-        final String scriptConstantBinary = GroovyTranslator.of("g").translate(tConstantBinary.asAdmin().getBytecode());
+        final String scriptConstantBinary = GroovyTranslator.of("g").translate(tConstantBinary.asAdmin().getBytecode()).getScript();
         assertEquals("g.withSack(1.0d, (java.util.function.BinaryOperator) {x,y -> x + y + 1}).V().sack()", scriptConstantBinary);
         assertThatScriptOk(scriptConstantBinary, "g", g);
 
         final Traversal<Vertex,Double> tSupplierBinary = g.withSack(Lambda.supplier("1.0d"), Lambda.<Double>binaryOperator("x,y -> x + y + 1")).V().sack();
-        final String scriptSupplierBinary = GroovyTranslator.of("g").translate(tSupplierBinary.asAdmin().getBytecode());
+        final String scriptSupplierBinary = GroovyTranslator.of("g").translate(tSupplierBinary.asAdmin().getBytecode()).getScript();
         assertEquals("g.withSack((java.util.function.Supplier) {1.0d}, (java.util.function.BinaryOperator) {x,y -> x + y + 1}).V().sack()", scriptSupplierBinary);
         assertThatScriptOk(scriptSupplierBinary, "g", g);
     }
@@ -168,7 +169,7 @@
         //
         assertEquals(24, t.getSideEffects().<Number>get("lengthSum").intValue());
 
-        final String script = GroovyTranslator.of("g").translate(t.getBytecode());
+        final String script = GroovyTranslator.of("g").translate(t.getBytecode()).getScript();
         assertEquals("g.withStrategies(org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.TranslationStrategy.instance())" +
                         ".withSideEffect(\"lengthSum\",(int) 0).withSack((int) 1)" +
                         ".V()" +
@@ -188,7 +189,7 @@
         final String script = GroovyTranslator.of("g").translate(g.V().id().is(new LinkedHashMap<Object,Object>() {{
             put(3, "32");
             put(Arrays.asList(1, 2, 3.1d), 4);
-        }}).asAdmin().getBytecode());
+        }}).asAdmin().getBytecode()).getScript();
         assertEquals("g.V().id().is([((int) 3):(\"32\"),([(int) 1, (int) 2, 3.1d]):((int) 4)])", script);
         assertThatScriptOk(script, "g", g);
     }
@@ -198,7 +199,7 @@
         final TinkerGraph graph = TinkerFactory.createModern();
         final GraphTraversalSource g = graph.traversal();
         final Function identity = new Lambda.OneArgLambda("it.get()", "gremlin-groovy");
-        final String script = GroovyTranslator.of("g").translate(g.inject(Collections.emptyMap()).map(identity).asAdmin().getBytecode());
+        final String script = GroovyTranslator.of("g").translate(g.inject(Collections.emptyMap()).map(identity).asAdmin().getBytecode()).getScript();
         assertEquals("g.inject([]).map({it.get()})", script);
         assertThatScriptOk(script, "g", g);
     }
@@ -237,7 +238,7 @@
 
     @Test
     public void shouldHandleOrder() {
-        assertTranslation("Order.decr", Order.decr);
+        assertTranslation("Order.shuffle", Order.shuffle);
     }
 
     @Test
@@ -258,12 +259,12 @@
 
         // without type translation we get uglinesss
         final String scriptBad = GroovyTranslator.of("g").
-                translate(g.inject(notSillyEnough).asAdmin().getBytecode());
+                translate(g.inject(notSillyEnough).asAdmin().getBytecode()).getScript();
         assertEquals(String.format("g.inject(%s)", "not silly enough:100"), scriptBad);
 
         // with type translation we get valid gremlin
-        final String scriptGood = GroovyTranslator.of("g", new SillyClassTranslator()).
-                translate(g.inject(notSillyEnough).asAdmin().getBytecode());
+        final String scriptGood = GroovyTranslator.of("g", new SillyClassTranslator(false)).
+                translate(g.inject(notSillyEnough).asAdmin().getBytecode()).getScript();
         assertEquals(String.format("g.inject(org.apache.tinkerpop.gremlin.groovy.jsr223.GroovyTranslatorTest.SillyClass.from('%s', (int) %s))", notSillyEnough.getX(), notSillyEnough.getY()), scriptGood);
         assertThatScriptOk(scriptGood, "g", g);
 
@@ -291,7 +292,7 @@
                 .property("name", "Foo\u0020Bar")
                 .property("age", 25)
                 .property("special", "`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?")
-                .asAdmin().getBytecode());
+                .asAdmin().getBytecode()).getScript();
 
         assertEquals("g.addV(\"customer\")" +
                         ".property(\"customer_id\",501L)" +
@@ -309,7 +310,7 @@
         final Object id1 = "customer:10:foo\u0020bar\u0020\u0024100#90"; // customer:10:foo bar $100#90
         final Vertex vertex1 = DetachedVertex.build().setLabel("customer").setId(id1)
                 .create();
-        final String script1 = GroovyTranslator.of("g").translate(g.inject(vertex1).asAdmin().getBytecode());
+        final String script1 = GroovyTranslator.of("g").translate(g.inject(vertex1).asAdmin().getBytecode()).getScript();
         assertEquals("g.inject(new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex(" +
                         "\"customer:10:foo bar \\$100#90\"," +
                         "\"customer\", Collections.emptyMap()))",
@@ -319,7 +320,7 @@
         final Object id2 = "user:20:foo\\u0020bar\\u005c\\u0022mr\\u005c\\u0022\\u00241000#50"; // user:20:foo\u0020bar\u005c\u0022mr\u005c\u0022\u00241000#50
         final Vertex vertex2 = DetachedVertex.build().setLabel("user").setId(id2)
                 .create();
-        final String script2 = GroovyTranslator.of("g").translate(g.inject(vertex2).asAdmin().getBytecode());
+        final String script2 = GroovyTranslator.of("g").translate(g.inject(vertex2).asAdmin().getBytecode()).getScript();
         assertEquals("g.inject(new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex(" +
                         "\"user:20:foo\\\\u0020bar\\\\u005c\\\\u0022mr\\\\u005c\\\\u0022\\\\u00241000#50\"," +
                         "\"user\", Collections.emptyMap()))",
@@ -331,7 +332,7 @@
                 .setOutV((DetachedVertex) vertex1)
                 .setInV((DetachedVertex) vertex2)
                 .create();
-        final String script3 = GroovyTranslator.of("g").translate(g.inject(edge).asAdmin().getBytecode());
+        final String script3 = GroovyTranslator.of("g").translate(g.inject(edge).asAdmin().getBytecode()).getScript();
         assertEquals("g.inject(new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedEdge(" +
                         "\"knows:30:foo bar \\$100:\\\\u0020\\\\u0024500#70\"," +
                         "\"knows\",Collections.emptyMap()," +
@@ -342,7 +343,7 @@
 
         final String script4 = GroovyTranslator.of("g").translate(
                 g.addE("knows").from(vertex1).to(vertex2).property("when", "2018/09/21")
-                        .asAdmin().getBytecode());
+                        .asAdmin().getBytecode()).getScript();
         assertEquals("g.addE(\"knows\")" +
                         ".from(new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex(\"customer:10:foo bar \\$100#90\",\"customer\", Collections.emptyMap()))" +
                         ".to(new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex(\"user:20:foo\\\\u0020bar\\\\u005c\\\\u0022mr\\\\u005c\\\\u0022\\\\u00241000#50\",\"user\", Collections.emptyMap()))" +
@@ -359,9 +360,9 @@
     }
 
     private void assertTranslation(final String expectedTranslation, final Object... objs) {
-        final String script = GroovyTranslator.of("g").translate(g.inject(objs).asAdmin().getBytecode());
-        assertEquals(String.format("g.inject(%s)", expectedTranslation), script);
-        assertThatScriptOk(script, "g", g);
+        final Script script = GroovyTranslator.of("g").translate(g.inject(objs).asAdmin().getBytecode());
+        assertEquals(String.format("g.inject(%s)", expectedTranslation), script.getScript());
+        assertThatScriptOk(script.getScript(), "g", g);
     }
 
     private void assertThatScriptOk(final String s, final Object... args) {
@@ -403,13 +404,18 @@
 
     public static class SillyClassTranslator extends GroovyTranslator.DefaultTypeTranslator {
 
+        public SillyClassTranslator(final boolean withParameters) {
+            super(withParameters);
+        }
+
         @Override
-        protected String convertToString(final Object object) {
-            if (object instanceof SillyClass)
-                return String.format("org.apache.tinkerpop.gremlin.groovy.jsr223.GroovyTranslatorTest.SillyClass.from('%s', (int) %s)",
-                        ((SillyClass) object).getX(), ((SillyClass) object).getY());
-            else
-                return super.convertToString(object);
+        protected Script convertToScript(final Object object) {
+            if (object instanceof SillyClass) {
+                return script.append(String.format("org.apache.tinkerpop.gremlin.groovy.jsr223.GroovyTranslatorTest.SillyClass.from('%s', (int) %s)",
+                        ((SillyClass) object).getX(), ((SillyClass) object).getY()));
+            } else {
+                return super.convertToScript(object);
+            }
         }
     }
 
@@ -417,7 +423,7 @@
 
         @Override
         public Translator.ScriptTranslator.TypeTranslator createTypeTranslator() {
-            return new SillyClassTranslator();
+            return new SillyClassTranslator(false);
         }
     }
 }
diff --git a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/ParameterizedGroovyTranslatorComputerProvider.java b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/ParameterizedGroovyTranslatorComputerProvider.java
new file mode 100644
index 0000000..3c948fa
--- /dev/null
+++ b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/ParameterizedGroovyTranslatorComputerProvider.java
@@ -0,0 +1,40 @@
+/*
+ *  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.groovy.jsr223;
+
+import org.apache.tinkerpop.gremlin.GraphProvider;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.tinkergraph.process.computer.TinkerGraphComputer;
+
+/**
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ */
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.computer.GraphComputerTest",
+        method = "shouldSucceedWithProperTraverserRequirements",
+        reason = "Reason requires investigation")
+@GraphProvider.Descriptor(computer = TinkerGraphComputer.class)
+public class ParameterizedGroovyTranslatorComputerProvider extends ParameterizedGroovyTranslatorProvider {
+
+    @Override
+    public GraphTraversalSource traversal(final Graph graph) {
+        return super.traversal(graph).withComputer();
+    }
+}
\ No newline at end of file
diff --git a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/ParameterizedGroovyTranslatorProcessComputerTest.java b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/ParameterizedGroovyTranslatorProcessComputerTest.java
new file mode 100644
index 0000000..e0cad35
--- /dev/null
+++ b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/ParameterizedGroovyTranslatorProcessComputerTest.java
@@ -0,0 +1,32 @@
+/*
+ *  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.groovy.jsr223;
+
+import org.apache.tinkerpop.gremlin.GraphProviderClass;
+import org.apache.tinkerpop.gremlin.process.ProcessComputerSuite;
+import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
+import org.junit.runner.RunWith;
+
+/**
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ */
+@RunWith(ProcessComputerSuite.class)
+@GraphProviderClass(provider = ParameterizedGroovyTranslatorComputerProvider.class, graph = TinkerGraph.class)
+public class ParameterizedGroovyTranslatorProcessComputerTest {
+}
\ No newline at end of file
diff --git a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/ParameterizedGroovyTranslatorProcessStandardTest.java b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/ParameterizedGroovyTranslatorProcessStandardTest.java
new file mode 100644
index 0000000..d00a53c
--- /dev/null
+++ b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/ParameterizedGroovyTranslatorProcessStandardTest.java
@@ -0,0 +1,32 @@
+/*
+ *  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.groovy.jsr223;
+
+import org.apache.tinkerpop.gremlin.GraphProviderClass;
+import org.apache.tinkerpop.gremlin.process.ProcessStandardSuite;
+import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
+import org.junit.runner.RunWith;
+
+/**
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ */
+@RunWith(ProcessStandardSuite.class)
+@GraphProviderClass(provider = ParameterizedGroovyTranslatorProvider.class, graph = TinkerGraph.class)
+public class ParameterizedGroovyTranslatorProcessStandardTest {
+}
\ No newline at end of file
diff --git a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/ParameterizedGroovyTranslatorProvider.java b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/ParameterizedGroovyTranslatorProvider.java
new file mode 100644
index 0000000..56466a5
--- /dev/null
+++ b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/ParameterizedGroovyTranslatorProvider.java
@@ -0,0 +1,223 @@
+/*
+ *  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.groovy.jsr223;
+
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.TranslationStrategy;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.util.TinkerGraphProvider;
+
+/**
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ */
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.ProfileTest",
+        method = "*",
+        reason = "Tests for profile() are not supported for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.branch.BranchTest",
+        method = "g_V_branchXlabel_eq_person__a_bX_optionXa__ageX_optionXb__langX_optionXb__nameX",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.branch.ChooseTest",
+        method = "g_V_chooseXlabel_eqXpersonX__outXknowsX__inXcreatedXX_name",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.filter.DedupTest",
+        method = "g_V_both_name_order_byXa_bX_dedup_value",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.filter.FilterTest",
+        method = "g_E_filterXfalseX",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.filter.FilterTest",
+        method = "g_E_filterXtrueX",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.filter.FilterTest",
+        method = "g_V_filterXfalseX",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.filter.FilterTest",
+        method = "g_V_filterXlang_eq_javaX",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.filter.FilterTest",
+        method = "g_V_filterXname_startsWith_m_OR_name_startsWith_pX",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.filter.FilterTest",
+        method = "g_V_filterXtrueX",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.filter.FilterTest",
+        method = "g_VX1X_filterXage_gt_30X",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.filter.FilterTest",
+        method = "g_VX1X_out_filterXage_gt_30X",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.filter.FilterTest",
+        method = "g_VX2X_filterXage_gt_30X",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.GroupTest",
+        method = "g_V_group_byXname_substring_1X_byXconstantX1XX",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.GroupTest",
+        method = "g_V_groupXaX_byXname_substring_1X_byXconstantX1XX_capXaX",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.filter.HasTest",
+        method = "g_V_outXcreatedX_hasXname__mapXlengthX_isXgtX3XXX_name",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.InjectTest",
+        method = "g_VX1X_out_name_injectXdanielX_asXaX_mapXlengthX_path",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.MapTest",
+        method = "g_VX1X_mapXnameX",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.MapTest",
+        method = "g_VX1X_out_mapXnameX_mapXlengthX",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.MapTest",
+        method = "g_VX1X_outE_label_mapXlengthX",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.MapTest",
+        method = "g_withPath_V_asXaX_out_mapXa_nameX",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.MapTest",
+        method = "g_withPath_V_asXaX_out_out_mapXa_name_it_nameX",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.OrderTest",
+        method = "g_V_hasLabelXpersonX_order_byXvalueXageX_descX_name",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.OrderTest",
+        method = "g_V_name_order_byXa1_b1X_byXb2_a2X",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.OrderTest",
+        method = "g_V_order_byXname_a1_b1X_byXname_b2_a2X_name",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.OrderTest",
+        method = "g_VX1X_hasXlabel_personX_mapXmapXint_ageXX_orderXlocalX_byXvalues_descX_byXkeys_ascX",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.branch.RepeatTest",
+        method = "g_V_repeatXbothX_untilXname_eq_marko_or_loops_gt_1X_groupCount_byXnameX",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.SackTest",
+        method = "g_withSackXmap__map_cloneX_V_out_out_sackXmap_a_nameX_sack",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.SideEffectTest",
+        method = "g_VX1X_out_sideEffectXincr_cX_name",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.SideEffectTest",
+        method = "g_VX1X_out_sideEffectXX_name",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.SideEffectTest",
+        method = "g_VX1X_sideEffectXstore_aX_name",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.SideEffectTest",
+        method = "g_withSideEffectsXa__linkedhashmapX_withSideEffectXb__arraylist__addAllX_withSideEffectXc__arrayList__addAllX_V_groupXaX_byXlabelX_byXcountX_sideEffectXb__1_2_3X_out_out_out_sideEffectXc__bob_danielX_capXaX",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.SideEffectTest",
+        method = "g_withSideEffectXa_0_sumX_V_out_sideEffectXsideEffectsXa_bulkXX_capXaX",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.SideEffectTest",
+        method = "g_withSideEffectXa_0X_V_out_sideEffectXsideEffectsXa_1XX_capXaX",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.SideEffectTest",
+        method = "g_withSideEffectXa__linkedhashmapX_V_out_groupCountXaX_byXlabelX_out_out_capXaX",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.SubgraphTest",
+        method = "g_V_withSideEffectXsgX_outEXknowsX_subgraphXsgX_name_capXsgX",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.SubgraphTest",
+        method = "g_V_withSideEffectXsgX_repeatXbothEXcreatedX_subgraphXsgX_outVX_timesX5X_name_dedup",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.SubgraphTest",
+        method = "g_withSideEffectXsgX_V_hasXname_danielXout_capXsgX",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.UnfoldTest",
+        method = "g_V_valueMap_unfold_mapXkeyX",
+        reason = "Tests that include lambdas are not supported by the test suite for remotes")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.ProgramTest",
+        method = "*",
+        reason = "Reason requires investigation")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.TraversalInterruptionTest",
+        method = "*",
+        reason = "Reason requires investigation")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.TraversalInterruptionComputerTest",
+        method = "*",
+        reason = "Reason requires investigation")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.EventStrategyProcessTest",
+        method = "*",
+        reason = "Strategy not properly supported by Bytecode based traversals")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.ElementIdStrategyProcessTest",
+        method = "*",
+        reason = "Strategy not properly supported by Bytecode based traversals")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.CoreTraversalTest",
+        method = "shouldNeverPropagateANoBulkTraverser",
+        reason = "Reason requires investigation")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.ReadTest",
+        method = "*",
+        reason = "read and write tests don't translate locally well because of calling iterate() inside read()/write() add a none()")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.WriteTest",
+        method = "*",
+        reason = "read and write tests don't translate locally well because of calling iterate() inside read()/write() add a none()")
+public class ParameterizedGroovyTranslatorProvider extends TinkerGraphProvider {
+    @Override
+    public GraphTraversalSource traversal(final Graph graph) {
+        final GraphTraversalSource g = graph.traversal();
+        return g.withStrategies(new TranslationStrategy(g, GroovyTranslator.of("g", true), true));
+    }
+}
\ No newline at end of file
diff --git a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/ParameterizedGroovyTranslatorTest.java b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/ParameterizedGroovyTranslatorTest.java
new file mode 100644
index 0000000..fbd6f56
--- /dev/null
+++ b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/ParameterizedGroovyTranslatorTest.java
@@ -0,0 +1,664 @@
+/*
+ *  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.groovy.jsr223;
+
+import org.apache.commons.configuration2.MapConfiguration;
+import org.apache.tinkerpop.gremlin.jsr223.TranslatorCustomizer;
+import org.apache.tinkerpop.gremlin.process.traversal.Compare;
+import org.apache.tinkerpop.gremlin.process.traversal.Order;
+import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.Pop;
+import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
+import org.apache.tinkerpop.gremlin.process.traversal.Scope;
+import org.apache.tinkerpop.gremlin.process.traversal.Script;
+import org.apache.tinkerpop.gremlin.process.traversal.Translator;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.TranslationStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.util.AndP;
+import org.apache.tinkerpop.gremlin.structure.Column;
+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.T;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedEdge;
+import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex;
+import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerFactory;
+import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
+import org.apache.tinkerpop.gremlin.util.function.Lambda;
+import org.junit.Test;
+
+import javax.script.Bindings;
+import javax.script.ScriptException;
+import javax.script.SimpleBindings;
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.UUID;
+import java.util.function.Function;
+
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ *  test {@link GroovyTranslator} which return parameterized result, covers:
+ *   - parameterized script checking
+ *   - binding checking
+ *   - eval result checking
+ *
+ *  <p>
+ *  {@link GroovyTranslatorTest } is used to test {@link GroovyTranslator}, both test cases looks the same
+ *  <p>
+ *
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ * @author Stark Arya (sandszhou.zj@alibaba-inc.com)
+ */
+public class ParameterizedGroovyTranslatorTest {
+
+    private Graph graph = TinkerGraph.open();
+    private GraphTraversalSource g = graph.traversal();
+    private static final GremlinGroovyScriptEngine parameterizedEngine = new GremlinGroovyScriptEngine(new TranslatorCustomizer() {
+        @Override
+        public Translator.ScriptTranslator.TypeTranslator createTypeTranslator() {
+            return new GroovyTranslator.DefaultTypeTranslator(true);
+        }
+    });
+
+    @Test
+    public void shouldHandleStrategies() throws Exception {
+        final TinkerGraph graph = TinkerFactory.createModern();
+        final GraphTraversalSource g = graph.traversal().withStrategies(SubgraphStrategy.create(new MapConfiguration(new HashMap<String, Object>() {{
+            put(SubgraphStrategy.VERTICES, __.has("name", "marko"));
+        }})));
+        final Bindings bindings = new SimpleBindings();
+        bindings.put("g", g);
+        Traversal.Admin<Vertex, Object> traversal = parameterizedEngine.eval(g.V().values("name").asAdmin().getBytecode(), bindings, "g");
+        assertEquals("marko", traversal.next());
+        assertFalse(traversal.hasNext());
+        //
+        traversal = parameterizedEngine.eval(g.withoutStrategies(SubgraphStrategy.class).V().count().asAdmin().getBytecode(), bindings, "g");
+        assertEquals(new Long(6), traversal.next());
+        assertFalse(traversal.hasNext());
+        //
+        traversal = parameterizedEngine.eval(g.withStrategies(SubgraphStrategy.create(new MapConfiguration(new HashMap<String, Object>() {{
+            put(SubgraphStrategy.VERTICES, __.has("name", "marko"));
+        }})), ReadOnlyStrategy.instance()).V().values("name").asAdmin().getBytecode(), bindings, "g");
+        assertEquals("marko", traversal.next());
+        assertFalse(traversal.hasNext());
+    }
+
+    @Test
+    public void shouldSupportStringSupplierLambdas() {
+        final TinkerGraph graph = TinkerFactory.createModern();
+        GraphTraversalSource g = graph.traversal();
+        g = g.withStrategies(new TranslationStrategy(g, GroovyTranslator.of("g", true), false));
+        final GraphTraversal.Admin<Vertex, Integer> t = g.withSideEffect("lengthSum", 0).withSack(1)
+                .V()
+                .filter(Lambda.predicate("it.get().label().equals('person')"))
+                .flatMap(Lambda.function("it.get().vertices(Direction.OUT)"))
+                .map(Lambda.<Traverser<Object>, Integer>function("it.get().value('name').length()"))
+                .sideEffect(Lambda.consumer("{ x -> x.sideEffects(\"lengthSum\", x.<Integer>sideEffects('lengthSum') + x.get()) }"))
+                .order().by(Lambda.comparator("a,b -> a <=> b"))
+                .sack(Lambda.biFunction("{ a,b -> a + b }"))
+                .asAdmin();
+
+        final List<Integer> sacks = new ArrayList<>();
+        final List<Integer> lengths = new ArrayList<>();
+        while (t.hasNext()) {
+            final Traverser.Admin<Integer> traverser = t.nextTraverser();
+            sacks.add(traverser.sack());
+            lengths.add(traverser.get());
+        }
+        assertFalse(t.hasNext());
+        //
+        assertEquals(6, lengths.size());
+        assertEquals(3, lengths.get(0).intValue());
+        assertEquals(3, lengths.get(1).intValue());
+        assertEquals(3, lengths.get(2).intValue());
+        assertEquals(4, lengths.get(3).intValue());
+        assertEquals(5, lengths.get(4).intValue());
+        assertEquals(6, lengths.get(5).intValue());
+        ///
+        assertEquals(6, sacks.size());
+        assertEquals(4, sacks.get(0).intValue());
+        assertEquals(4, sacks.get(1).intValue());
+        assertEquals(4, sacks.get(2).intValue());
+        assertEquals(5, sacks.get(3).intValue());
+        assertEquals(6, sacks.get(4).intValue());
+        assertEquals(7, sacks.get(5).intValue());
+        //
+        assertEquals(24, t.getSideEffects().<Number>get("lengthSum").intValue());
+
+        final Script script = GroovyTranslator.of("g", true).translate(t.getBytecode());
+        final Bindings bindings = new SimpleBindings();
+        script.getParameters().ifPresent(bindings::putAll);
+        assertEquals(9, bindings.size());
+        assertEquals("lengthSum", bindings.get("_args_0"));
+        assertEquals(Integer.valueOf(0), bindings.get("_args_1"));
+        assertEquals(Integer.valueOf(1), bindings.get("_args_2"));
+        assertEquals(Lambda.predicate("it.get().label().equals('person')"), bindings.get("_args_3"));
+        assertEquals(Lambda.function("it.get().vertices(Direction.OUT)"), bindings.get("_args_4"));
+        assertEquals(Lambda.<Traverser<Object>, Integer>function("it.get().value('name').length()"), bindings.get("_args_5"));
+        assertEquals(Lambda.consumer("{ x -> x.sideEffects(\"lengthSum\", x.<Integer>sideEffects('lengthSum') + x.get()) }"), bindings.get("_args_6"));
+        assertEquals(Lambda.comparator("a,b -> a <=> b"), bindings.get("_args_7"));
+        assertEquals(Lambda.biFunction("{ a,b -> a + b }"), bindings.get("_args_8"));
+        assertEquals("g.withStrategies(org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.TranslationStrategy.instance())" +
+                        ".withSideEffect(_args_0,_args_1).withSack(_args_2)" +
+                        ".V()" +
+                        ".filter(_args_3)" +
+                        ".flatMap(_args_4)" +
+                        ".map(_args_5)" +
+                        ".sideEffect(_args_6)" +
+                        ".order().by(_args_7)" +
+                        ".sack(_args_8)",
+                script.getScript());
+    }
+
+    @Test
+    public void shouldHandleArray() {
+        final TinkerGraph graph = TinkerFactory.createModern();
+        final GraphTraversalSource g = graph.traversal();
+        final Script script = GroovyTranslator.of("g", true).translate(g.V().has(T.id, P.within(new ArrayList() {{
+            add(1);
+            add(2);
+            add(3);
+            add(4);
+            add(5);
+        }})).asAdmin().getBytecode());
+        final Bindings bindings = new SimpleBindings();
+        script.getParameters().ifPresent(bindings::putAll);
+        assertEquals(5, bindings.size());
+        assertEquals(Integer.valueOf(1), bindings.get("_args_0"));
+        assertEquals(Integer.valueOf(2), bindings.get("_args_1"));
+        assertEquals(Integer.valueOf(3), bindings.get("_args_2"));
+        assertEquals(Integer.valueOf(4), bindings.get("_args_3"));
+        assertEquals(Integer.valueOf(5), bindings.get("_args_4"));
+        assertEquals("g.V().has(T.id,P.within([_args_0, _args_1, _args_2, _args_3, _args_4]))", script.getScript());
+
+        final Script standard = GroovyTranslator.of("g").translate(g.V().has(T.id, P.within(new ArrayList() {{
+            add(1);
+            add(2);
+            add(3);
+            add(4);
+            add(5);
+        }})).asAdmin().getBytecode());
+
+        bindings.put("g", g);
+        assertParameterizedScriptOk(standard.getScript(), script.getScript(), bindings, true);
+    }
+
+    @Test
+    public void shouldHandleSet() {
+        final TinkerGraph graph = TinkerFactory.createModern();
+        final GraphTraversalSource g = graph.traversal();
+        final Script script = GroovyTranslator.of("g", true).translate(g.V().id().is(new HashSet<Object>() {{
+            add(3);
+            add(Arrays.asList(1, 2, 3.1d));
+            add(3);
+            add("3");
+        }}).asAdmin().getBytecode());
+        final Bindings bindings = new SimpleBindings();
+        script.getParameters().ifPresent(bindings::putAll);
+        assertEquals(5, bindings.size());
+        assertEquals(Integer.valueOf(3), bindings.get("_args_0"));
+        assertEquals("3", bindings.get("_args_1"));
+        assertEquals(Integer.valueOf(1), bindings.get("_args_2"));
+        assertEquals(Integer.valueOf(2), bindings.get("_args_3"));
+        assertEquals(Double.valueOf(3.1), bindings.get("_args_4"));
+        assertEquals("g.V().id().is([_args_0, _args_1, [_args_2, _args_3, _args_4]] as Set)", script.getScript());
+
+        final Script standard = GroovyTranslator.of("g" ).translate(g.V().id().is(new HashSet<Object>() {{
+            add(3);
+            add(Arrays.asList(1, 2, 3.1d));
+            add(3);
+            add("3");
+        }}).asAdmin().getBytecode());
+        bindings.put("g", g);
+        assertParameterizedScriptOk(standard.getScript(), script.getScript(), bindings, true);
+    }
+
+    @Test
+    public void shouldHandleMaps() {
+        final TinkerGraph graph = TinkerFactory.createModern();
+        final GraphTraversalSource g = graph.traversal();
+        final Script script = GroovyTranslator.of("g", true).translate(g.V().id().is(new LinkedHashMap<Object,Object>() {{
+            put(3, "32");
+            put(Arrays.asList(1, 2, 3.1d), 4);
+        }}).asAdmin().getBytecode());
+        final Bindings bindings = new SimpleBindings();
+        script.getParameters().ifPresent(bindings::putAll);
+        assertEquals(6, bindings.size());
+        assertEquals(Integer.valueOf(3), bindings.get("_args_0"));
+        assertEquals("32", bindings.get("_args_1"));
+        assertEquals(Integer.valueOf(1), bindings.get("_args_2"));
+        assertEquals(Integer.valueOf(2), bindings.get("_args_3"));
+        assertEquals(Double.valueOf(3.1), bindings.get("_args_4"));
+        assertEquals(Integer.valueOf(4), bindings.get("_args_5"));
+        assertEquals("g.V().id().is([(_args_0):(_args_1),([_args_2, _args_3, _args_4]):(_args_5)])", script.getScript());
+        final Script standard = GroovyTranslator.of("g").translate(g.V().id().is(new LinkedHashMap<Object,Object>() {{
+            put(3, "32");
+            put(Arrays.asList(1, 2, 3.1d), 4);
+        }}).asAdmin().getBytecode());
+        bindings.put("g", g);
+        assertParameterizedScriptOk(standard.getScript(), script.getScript(), bindings, true);
+    }
+
+    @Test
+    public void shouldHandleEmptyMaps() {
+        final TinkerGraph graph = TinkerFactory.createModern();
+        final GraphTraversalSource g = graph.traversal();
+        final Function identity = new Lambda.OneArgLambda("it.get()", "gremlin-groovy");
+        final Script script = GroovyTranslator.of("g", true).translate(g.inject(Collections.emptyMap()).map(identity).asAdmin().getBytecode());
+        final Bindings bindings = new SimpleBindings();
+        script.getParameters().ifPresent(bindings::putAll);
+        assertEquals(1, bindings.size());
+        assertEquals(identity, bindings.get("_args_0"));
+        assertEquals("g.inject([]).map(_args_0)", script.getScript());
+        bindings.put("g", g);
+        assertThatScriptOk(script.getScript(), bindings);
+    }
+
+    @Test
+    public void shouldHandleDate() {
+        final Calendar c = Calendar.getInstance();
+        c.set(1975, Calendar.SEPTEMBER, 7);
+        final Date d = c.getTime();
+        assertParameterizedTranslation(String.format("new java.util.Date(%s)", d.getTime()), d);
+    }
+
+    @Test
+    public void shouldHandlePredicate() {
+        final P p = new P(Compare.eq, 10);
+        assertParameterizedTranslation(String.format("new java.util.Date(%s)", p.toString()), 10);
+    }
+
+    @Test
+    public void shouldHandleTimestamp() {
+        final Calendar c = Calendar.getInstance();
+        c.set(1975, Calendar.SEPTEMBER, 7);
+        final Timestamp t = new Timestamp(c.getTime().getTime());
+        assertParameterizedTranslation(String.format("new java.sql.Timestamp(%s)", t.getTime()), t);
+    }
+
+    @Test
+    public void shouldHandleUuid() {
+        final UUID uuid = UUID.fromString("ffffffff-fd49-1e4b-0000-00000d4b8a1d");
+        assertParameterizedTranslation(String.format("java.util.UUID.fromString('%s')", uuid), uuid);
+    }
+
+    @Test
+    public void shouldHandleClass() {
+        final Class cls = Vertex.class;
+        assertParameterizedTranslation(String.format("%s", cls), cls.getCanonicalName());
+    }
+
+    @Test
+    public void shouldHandleBarrier() {
+        final SackFunctions.Barrier barrier = SackFunctions.Barrier.normSack;
+        assertNonParameterizedTranslation(String.format("SackFunctions.Barrier.%s", barrier), barrier);
+    }
+
+    @Test
+    public void shouldHandleCardinality() {
+        final VertexProperty.Cardinality cardinality = VertexProperty.Cardinality.set;
+        assertNonParameterizedTranslation(String.format("VertexProperty.Cardinality.%s", cardinality), cardinality);
+    }
+
+    @Test
+    public void shouldHandlePick() {
+        final TraversalOptionParent.Pick pick = TraversalOptionParent.Pick.any;
+        assertNonParameterizedTranslation(String.format("TraversalOptionParent.Pick.%s", pick), pick);
+    }
+
+    @Test
+    public void shouldHandleColumn() {
+        assertNonParameterizedTranslation("Column.keys", Column.keys);
+    }
+
+    @Test
+    public void shouldHandleDirection() {
+        assertNonParameterizedTranslation("Direction.BOTH", Direction.BOTH);
+    }
+
+    @Test
+    public void shouldHandleOrder() {
+        assertNonParameterizedTranslation("Order.shuffle", Order.shuffle);
+    }
+
+    @Test
+    public void shouldHandlePop() {
+        assertNonParameterizedTranslation("Pop.last", Pop.last);
+    }
+
+    @Test
+    public void shouldHandleScope() {
+        assertNonParameterizedTranslation("Scope.local", Scope.local);
+    }
+
+    @Test
+    public void shouldIncludeCustomTypeTranslationForSomethingSilly() throws Exception {
+        final TinkerGraph graph = TinkerGraph.open();
+        final ParameterizedSillyClass notSillyEnough = ParameterizedSillyClass.from("not silly enough", 100);
+        final GraphTraversalSource g = graph.traversal();
+
+        // without type translation we get uglinesss
+        final Script parameterizedScriptBad = GroovyTranslator.of("g", true).
+                translate(g.inject(notSillyEnough).asAdmin().getBytecode());
+        Bindings bindings = new SimpleBindings();
+        parameterizedScriptBad.getParameters().ifPresent(bindings::putAll);
+        assertEquals(String.format("g.inject(%s)", "_args_0"), parameterizedScriptBad.getScript());
+        assertEquals(1, bindings.size());
+        assertEquals(notSillyEnough, bindings.get("_args_0"));
+        bindings.clear();
+
+        // with type translation we get valid gremlin
+        final Script parameterizedScriptGood = GroovyTranslator.of("g", new ParameterizedSillyClassTranslatorCustomizer().createTypeTranslator()).
+                translate(g.inject(notSillyEnough).asAdmin().getBytecode());
+        parameterizedScriptGood.getParameters().ifPresent(bindings::putAll);
+        assertEquals(2, bindings.size());
+        assertEquals(notSillyEnough.getX(), bindings.get("_args_0"));
+        assertEquals(notSillyEnough.getY(), bindings.get("_args_1"));
+        assertEquals("g.inject(org.apache.tinkerpop.gremlin.groovy.jsr223.ParameterizedGroovyTranslatorTest.ParameterizedSillyClass.from(_args_0,_args_1))", parameterizedScriptGood.getScript());
+        bindings.put("g", g);
+        assertThatScriptOk(parameterizedScriptGood.getScript(), bindings);
+
+        final GremlinGroovyScriptEngine customEngine = new GremlinGroovyScriptEngine(new ParameterizedSillyClassTranslatorCustomizer());
+        final Traversal t = customEngine.eval(g.inject(notSillyEnough).asAdmin().getBytecode(), bindings, "g");
+        final ParameterizedSillyClass sc = (ParameterizedSillyClass) t.next();
+        assertEquals(notSillyEnough.getX(), sc.getX());
+        assertEquals(notSillyEnough.getY(), sc.getY());
+        assertThat(t.hasNext(), is(false));
+    }
+
+    @Test
+    public void shouldHaveValidToString() {
+        assertEquals("translator[h:gremlin-groovy]", GroovyTranslator.of("h", true).toString());
+    }
+
+    @Test
+    public void shouldEscapeStrings() {
+        final TinkerGraph graph = TinkerFactory.createModern();
+        final GraphTraversalSource g = graph.traversal();
+        final Script script = GroovyTranslator.of("g", true).translate(g.addV("customer")
+                .property("customer_id", 501L)
+                .property("name", "Foo\u0020Bar")
+                .property("age", 25)
+                .property("special", "`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?")
+                .asAdmin().getBytecode());
+        final Bindings bindings = new SimpleBindings();
+        script.getParameters().ifPresent(bindings::putAll);
+        assertEquals(9, bindings.size());
+        assertEquals("customer", bindings.get("_args_0"));
+        assertEquals("customer_id", bindings.get("_args_1"));
+        assertEquals(Long.valueOf(501), bindings.get("_args_2"));
+        assertEquals("name", bindings.get("_args_3"));
+        assertEquals("Foo\u0020Bar", bindings.get("_args_4"));
+        assertEquals("age", bindings.get("_args_5"));
+        assertEquals(Integer.valueOf(25), bindings.get("_args_6"));
+        assertEquals("special", bindings.get("_args_7"));
+        assertEquals("`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?", bindings.get("_args_8"));
+        assertEquals("g.addV(_args_0).property(_args_1,_args_2).property(_args_3,_args_4).property(_args_5,_args_6).property(_args_7,_args_8)", script.getScript());
+
+        final Script standard = GroovyTranslator.of("g").translate(g.addV("customer")
+                .property("customer_id", 501L)
+                .property("name", "Foo\u0020Bar")
+                .property("age", 25)
+                .property("special", "`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?")
+                .asAdmin().getBytecode());
+
+        bindings.put("g", g);
+        //add vertex will return different vertex id
+        assertParameterizedScriptOk(standard.getScript(), script.getScript(), bindings, false);
+    }
+
+    @Test
+    public void shouldHandleVertexAndEdge() {
+        final TinkerGraph graph = TinkerFactory.createModern();
+        final GraphTraversalSource g = graph.traversal();
+
+        final Object id1 = "customer:10:foo\u0020bar\u0020\u0024100#90"; // customer:10:foo bar $100#90
+        final Vertex vertex1 = DetachedVertex.build().setLabel("customer").setId(id1)
+                .create();
+        final Script script1 = GroovyTranslator.of("g", true).translate(g.inject(vertex1).asAdmin().getBytecode());
+        final Bindings bindings = new SimpleBindings();
+        script1.getParameters().ifPresent(bindings::putAll);
+        assertEquals(2, bindings.size());
+        assertEquals(id1, bindings.get("_args_0"));
+        assertEquals("customer", bindings.get("_args_1"));
+        assertEquals("g.inject(new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex(_args_0,_args_1, Collections.emptyMap()))", script1.getScript());
+        final Script standard1 = GroovyTranslator.of("g").translate(g.inject(vertex1).asAdmin().getBytecode());
+        bindings.put("g", g);
+        // TinkerGraph not support string id
+        assertParameterizedScriptOk(standard1.getScript(), script1.getScript(), bindings, false);
+        bindings.clear();
+
+        final Object id2 = "user:20:foo\\u0020bar\\u005c\\u0022mr\\u005c\\u0022\\u00241000#50"; // user:20:foo\u0020bar\u005c\u0022mr\u005c\u0022\u00241000#50
+        final Vertex vertex2 = DetachedVertex.build().setLabel("user").setId(id2)
+                .create();
+        final Script script2 = GroovyTranslator.of("g", true).translate(g.inject(vertex2).asAdmin().getBytecode());
+        script2.getParameters().ifPresent(bindings::putAll);
+        assertEquals(2, bindings.size());
+        assertEquals(id2, bindings.get("_args_0"));
+        assertEquals("user", bindings.get("_args_1"));
+        assertEquals("g.inject(new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex(_args_0,_args_1, Collections.emptyMap()))", script2.getScript());
+        final Script standard2 = GroovyTranslator.of("g").translate(g.inject(vertex2).asAdmin().getBytecode());
+        bindings.put("g", g);
+        assertParameterizedScriptOk(standard2.getScript(), script2.getScript(), bindings, false);
+        bindings.clear();
+
+        final Object id3 = "knows:30:foo\u0020bar\u0020\u0024100:\\u0020\\u0024500#70";
+        final Edge edge = DetachedEdge.build().setLabel("knows").setId(id3)
+                .setOutV((DetachedVertex) vertex1)
+                .setInV((DetachedVertex) vertex2)
+                .create();
+        final Script script3 = GroovyTranslator.of("g", true).translate(g.inject(edge).asAdmin().getBytecode());
+        script3.getParameters().ifPresent(bindings::putAll);
+        assertEquals(6, bindings.size());
+        assertEquals(id3, bindings.get("_args_0"));
+        assertEquals("knows", bindings.get("_args_1"));
+        assertEquals(id1, bindings.get("_args_2"));
+        assertEquals("customer", bindings.get("_args_3"));
+        assertEquals(id2, bindings.get("_args_4"));
+        assertEquals("user", bindings.get("_args_5"));
+        assertEquals("g.inject(new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedEdge(_args_0,_args_1,Collections.emptyMap(),_args_2,_args_3,_args_4,_args_5))", script3.getScript());
+        final Script standard3 = GroovyTranslator.of("g").translate(g.inject(edge).asAdmin().getBytecode());
+        bindings.put("g", g);
+        assertParameterizedScriptOk(standard3.getScript(), script3.getScript(), bindings, false);
+        bindings.clear();
+
+        final Script script4 = GroovyTranslator.of("g", true).translate(
+                g.addE("knows").from(vertex1).to(vertex2).property("when", "2018/09/21")
+                        .asAdmin().getBytecode());
+        script4.getParameters().ifPresent(bindings::putAll);
+        assertEquals(7, bindings.size());
+        assertEquals("knows", bindings.get("_args_0"));
+        assertEquals(id1, bindings.get("_args_1"));
+        assertEquals("customer", bindings.get("_args_2"));
+        assertEquals(id2, bindings.get("_args_3"));
+        assertEquals("user", bindings.get("_args_4"));
+        assertEquals("when", bindings.get("_args_5"));
+        assertEquals("2018/09/21", bindings.get("_args_6"));
+        assertEquals("g.addE(_args_0).from(new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex(_args_1,_args_2, Collections.emptyMap())).to(new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex(_args_3,_args_4, Collections.emptyMap())).property(_args_5,_args_6)", script4.getScript());
+        final Script standard4 = GroovyTranslator.of("g").translate(
+                g.addE("knows").from(vertex1).to(vertex2).property("when", "2018/09/21")
+                        .asAdmin().getBytecode());
+        bindings.put("g", g);
+        assertParameterizedScriptOk(standard4.getScript(), script4.getScript(), bindings, false);
+        bindings.clear();
+
+        final Script script5 = GroovyTranslator.of("g", true).translate(g.V().has("age").asAdmin().getBytecode());
+        script5.getParameters().ifPresent(bindings::putAll);
+        assertEquals(1, bindings.size());
+        assertEquals("age", bindings.get("_args_0"));
+        assertEquals("g.V().has(_args_0)", script5.getScript());
+        final Script standard5 = GroovyTranslator.of("g").translate(g.V().has("age").asAdmin().getBytecode());
+        bindings.put("g", g);
+        // Ok, here we checking all the result
+        assertParameterizedScriptOk(standard5.getScript(), script5.getScript(), bindings, true);
+        bindings.clear();
+    }
+
+    private Object eval(final String s, final Bindings b) throws ScriptException {
+        return parameterizedEngine.eval(s, b);
+    }
+
+    private void assertParameterizedTranslation(final String expectedTranslation, final Object... objs) {
+        final Script script = GroovyTranslator.of("g", true).translate(g.inject(objs).asAdmin().getBytecode());
+        final Bindings bindings = new SimpleBindings();
+        script.getParameters().ifPresent(bindings::putAll);
+        assertEquals(1, bindings.size());
+        assertEquals(objs[0], bindings.get("_args_0"));
+        assertEquals(String.format("g.inject(_args_0)", expectedTranslation), script.getScript());
+
+        final Script standard = GroovyTranslator.of("g").translate(g.inject(objs).asAdmin().getBytecode());
+        bindings.put("g", g);
+        assertParameterizedScriptOk(standard.getScript(), script.getScript(), bindings, true);
+    }
+
+    private void assertNonParameterizedTranslation(final String expectedTranslation, final Object... objs) {
+        final Script script = GroovyTranslator.of("g", true).translate(g.inject(objs).asAdmin().getBytecode());
+        final Bindings bindings = new SimpleBindings();
+        script.getParameters().ifPresent(bindings::putAll);
+        assertEquals(0, bindings.size());
+        assertEquals(String.format("g.inject(%s)", expectedTranslation),  script.getScript());
+
+        final Script standard = GroovyTranslator.of("g").translate(g.inject(objs).asAdmin().getBytecode());
+        assertEquals(standard.getScript(), script.getScript());
+    }
+
+    private void assertThatScriptOk(final String s, Bindings bindings) {
+        try {
+            assertNotNull(eval(s, bindings));
+        } catch (ScriptException se) {
+            se.printStackTrace();
+            fail("Script should have eval'd");
+        }
+    }
+
+    private void assertParameterizedScriptOk(final String standardScript, final String checkingScript, final Bindings bindings, final boolean resultChecking) {
+        try {
+            System.out.println(standardScript + " " + checkingScript);
+            assertTrue(!standardScript.equals(checkingScript));
+            assertThatScriptOk(checkingScript, bindings);
+            assertEquals(eval(standardScript, bindings), eval(checkingScript, bindings));
+            if (resultChecking) {
+                Traversal.Admin<Vertex, Object> standardTraversal = (Traversal.Admin) eval(standardScript, bindings);
+                Traversal.Admin<Vertex, Object> checkingTraversal = (Traversal.Admin) eval(checkingScript, bindings);
+                while (standardTraversal.hasNext() && checkingTraversal.hasNext()) {
+                    // assertEquals(standardTraversal.next(), checkingTraversal.next());
+                    System.out.println(standardTraversal.next() +  " " + checkingTraversal.next());
+                }
+                assertEquals(standardTraversal.hasNext(), checkingTraversal.hasNext());
+            }
+        } catch (ScriptException se) {
+            se.printStackTrace();
+            fail("Script should have eval'd");
+        }
+    }
+
+    public static class ParameterizedSillyClass {
+
+        private final String x;
+        private final int y;
+
+        private ParameterizedSillyClass(final String x, final int y) {
+            this.x = x;
+            this.y = y;
+        }
+
+        public static ParameterizedSillyClass from(final String x, final int y) {
+            return new ParameterizedSillyClass(x, y);
+        }
+
+        public String getX() {
+            return x;
+        }
+
+        public int getY() {
+            return y;
+        }
+
+        public Object[] getArguments() {
+            return new Object[] {x,y};
+        }
+
+        @Override
+        public String toString() {
+            return String.format("org.apache.tinkerpop.gremlin.groovy.jsr223.ParameterizedGroovyTranslatorTest.ParameterizedSillyClass.from('%s', (int) %s)", getX(), getY());
+        }
+    }
+
+    public static class ParameterizedSillyClassTranslator extends  GroovyTranslator.DefaultTypeTranslator {
+        public ParameterizedSillyClassTranslator(final boolean withParameters) {
+           super(withParameters);
+        }
+
+        @Override
+        protected Script convertToScript(final Object object) {
+            if (object instanceof ParameterizedSillyClass) {
+                ParameterizedSillyClass obj = (ParameterizedSillyClass) object;
+                script.append(obj.getClass().getCanonicalName());
+                if (0 == obj.getArguments().length) {
+                    script.append(".").append("from").append("()");
+                } else {
+                    script.append(".").append("from").append("(");
+                    for (final Object argument: obj.getArguments()) {
+                        convertToScript(argument);
+                        script.append(",");
+                    }
+                    script.setCharAtEnd(')');
+                }
+                return script;
+            } else {
+                return super.convertToScript(object);
+            }
+        }
+    }
+
+    public static class ParameterizedSillyClassTranslatorCustomizer implements TranslatorCustomizer {
+
+        @Override
+        public Translator.ScriptTranslator.TypeTranslator createTypeTranslator() {
+            return new ParameterizedSillyClassTranslator(true);
+        }
+    }
+}
+
diff --git a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/util/DependencyGrabberIntegrateTest.java b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/util/DependencyGrabberIntegrateTest.java
index 850a62f..7441d22 100644
--- a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/util/DependencyGrabberIntegrateTest.java
+++ b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/util/DependencyGrabberIntegrateTest.java
@@ -36,7 +36,7 @@
  */
 public class DependencyGrabberIntegrateTest {
     private static final String GROUP_ID = "org.apache.tinkerpop";
-    private static final String VERSION = "3.3.7";
+    private static final String VERSION = "3.3.8";
 
     private static final GroovyClassLoader groovyClassLoader = new GroovyClassLoader();
     private static final File extTestDir = TestHelper.makeTestDataPath(DependencyGrabberIntegrateTest.class);
diff --git a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/util/TinkerGraphProvider.java b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/util/TinkerGraphProvider.java
index 89fdb11..29230bb 100644
--- a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/util/TinkerGraphProvider.java
+++ b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/util/TinkerGraphProvider.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.util;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.AbstractGraphProvider;
 import org.apache.tinkerpop.gremlin.LoadGraphWith;
 import org.apache.tinkerpop.gremlin.TestHelper;
diff --git a/gremlin-javascript/build/generate.groovy b/gremlin-javascript/build/generate.groovy
new file mode 100644
index 0000000..7a374c0
--- /dev/null
+++ b/gremlin-javascript/build/generate.groovy
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+
+import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph
+import org.apache.tinkerpop.gremlin.process.traversal.translator.JavascriptTranslator
+import org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine
+import org.apache.tinkerpop.gremlin.groovy.jsr223.ast.VarAsBindingASTTransformation
+import org.apache.tinkerpop.gremlin.groovy.jsr223.ast.RepeatASTTransformationCustomizer
+import org.apache.tinkerpop.gremlin.groovy.jsr223.GroovyCustomizer
+import org.codehaus.groovy.control.customizers.CompilationCustomizer
+import org.apache.tinkerpop.gremlin.features.FeatureReader
+
+import javax.script.SimpleBindings
+
+import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal
+
+// file is overwritten on each generation
+radishGremlinFile = new File("${projectBaseDir}/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js")
+
+// assumes globally unique scenario names for keys with list of Gremlin traversals as they appear
+gremlins = FeatureReader.parse("${projectBaseDir}")
+
+gremlinGroovyScriptEngine = new GremlinGroovyScriptEngine(new GroovyCustomizer() {
+    public CompilationCustomizer create() {
+        return new RepeatASTTransformationCustomizer(new VarAsBindingASTTransformation())
+    }
+})
+translator = JavascriptTranslator.of('g')
+g = traversal().withGraph(EmptyGraph.instance())
+bindings = new SimpleBindings()
+bindings.put('g', g)
+
+radishGremlinFile.withWriter('UTF-8') { Writer writer ->
+    writer.writeLine('/*\n' +
+            '* Licensed to the Apache Software Foundation (ASF) under one\n' +
+            '* or more contributor license agreements.  See the NOTICE file\n' +
+            '* distributed with this work for additional information\n' +
+            '* regarding copyright ownership.  The ASF licenses this file\n' +
+            '* to you under the Apache License, Version 2.0 (the\n' +
+            '* "License"); you may not use this file except in compliance\n' +
+            '* with the License.  You may obtain a copy of the License at\n' +
+            '* \n' +
+            '* http://www.apache.org/licenses/LICENSE-2.0\n' +
+            '* \n' +
+            '* Unless required by applicable law or agreed to in writing,\n' +
+            '* software distributed under the License is distributed on an\n' +
+            '* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n' +
+            '* KIND, either express or implied.  See the License for the\n' +
+            '* specific language governing permissions and limitations\n' +
+            '* under the License.\n' +
+            '*/\n')
+
+    writer.writeLine("\n\n//********************************************************************************")
+    writer.writeLine("//* Do NOT edit this file directly - generated by build/generate.groovy")
+    writer.writeLine("//********************************************************************************\n\n")
+
+    writer.writeLine(
+                    'const graphTraversalModule = require(\'../../lib/process/graph-traversal\');\n' +
+                    'const traversalModule = require(\'../../lib/process/traversal\');\n' +
+                    'const { TraversalStrategies, VertexProgramStrategy, OptionsStrategy } = require(\'../../lib/process/traversal-strategy\');\n' +
+                    'const __ = graphTraversalModule.statics;\n' +
+                    'const Barrier = traversalModule.barrier\n' +
+                    'const Cardinality = traversalModule.cardinality\n' +
+                    'const Column = traversalModule.column\n' +
+                    'const Direction = {\n' +
+                    '    BOTH: traversalModule.direction.both,\n' +
+                    '    IN: traversalModule.direction.in,\n' +
+                    '    OUT: traversalModule.direction.out\n' +
+                    '};\n' +
+                    'const P = traversalModule.P;\n' +
+                    'const Pick = traversalModule.pick\n' +
+                    'const Pop = traversalModule.pop\n' +
+                    'const Order = traversalModule.order\n' +
+                    'const Operator = traversalModule.operator\n' +
+                    'const Scope = traversalModule.scope\n' +
+                    'const T = traversalModule.t\n' +
+                    'const TextP = traversalModule.TextP\n' +
+                    'const WithOptions = traversalModule.withOptions\n')
+
+    writer.writeLine('const gremlins = {')
+    gremlins.each { k,v ->
+        writer.write("    ")
+        writer.write(k)
+        writer.write(": [")
+        def collected = v.collect{
+            def t = gremlinGroovyScriptEngine.eval(it, bindings)
+            [t, t.bytecode.bindings.keySet()]
+        }
+        def uniqueBindings = collected.collect{it[1]}.flatten().unique()
+        def gremlinItty = collected.iterator()
+        while (gremlinItty.hasNext()) {
+            def t = gremlinItty.next()[0]
+            writer.write("function({g")
+            if (!uniqueBindings.isEmpty()) {
+                writer.write(", ")
+                writer.write(uniqueBindings.join(", "))
+            }
+            writer.write("}) { return ")
+            writer.write(translator.translate(t.bytecode).script)
+            writer.write(" }")
+            if (gremlinItty.hasNext()) writer.write(', ')
+        }
+        writer.writeLine('], ')
+    }
+    writer.writeLine('}\n')
+
+    writer.writeLine('exports.gremlin = gremlins')
+}
+
+
diff --git a/gremlin-javascript/glv/GraphTraversalSource.template b/gremlin-javascript/glv/GraphTraversalSource.template
deleted file mode 100644
index c5e490c..0000000
--- a/gremlin-javascript/glv/GraphTraversalSource.template
+++ /dev/null
@@ -1,176 +0,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.
- */
-
-/**
- * @author Jorge Bay Gondra
- */
-'use strict';
-
-const { Traversal } = require('./traversal');
-const remote = require('../driver/remote-connection');
-const utils = require('../utils');
-const Bytecode = require('./bytecode');
-const { TraversalStrategies, VertexProgramStrategy, OptionsStrategy } = require('./traversal-strategy');
-
-
-/**
- * Represents the primary DSL of the Gremlin traversal machine.
- */
-class GraphTraversalSource {
-
-  /**
-   * Creates a new instance of {@link GraphTraversalSource}.
-   * @param {Graph} graph
-   * @param {TraversalStrategies} traversalStrategies
-   * @param {Bytecode} [bytecode]
-   * @param {Function} [graphTraversalSourceClass] Optional {@link GraphTraversalSource} constructor.
-   * @param {Function} [graphTraversalClass] Optional {@link GraphTraversal} constructor.
-   */
-  constructor(graph, traversalStrategies, bytecode, graphTraversalSourceClass, graphTraversalClass) {
-    this.graph = graph;
-    this.traversalStrategies = traversalStrategies;
-    this.bytecode = bytecode || new Bytecode();
-    this.graphTraversalSourceClass = graphTraversalSourceClass || GraphTraversalSource;
-    this.graphTraversalClass = graphTraversalClass || GraphTraversal;
-  }
-
-  /**
-   * @param remoteConnection
-   * @returns {GraphTraversalSource}
-   */
-  withRemote(remoteConnection) {
-    const traversalStrategy = new TraversalStrategies(this.traversalStrategies);
-    traversalStrategy.addStrategy(new remote.RemoteStrategy(remoteConnection));
-    return new this.graphTraversalSourceClass(this.graph, traversalStrategy, new Bytecode(this.bytecode), this.graphTraversalSourceClass, this.graphTraversalClass);
-  }
-
-  /**
-   * @param graphComputer
-   * @param workers
-   * @param result
-   * @param persist
-   * @param vertices
-   * @param edges
-   * @param configuration
-   * @returns {GraphTraversalSource}
-   */
-  withComputer(graphComputer, workers, result, persist, vertices, edges, configuration) {
-    return this.withStrategies(new VertexProgramStrategy({graphComputer: graphComputer,
-                           workers: workers, result: result, persist: persist, vertices: vertices, edges: edges,
-                           configuration: configuration}));
-  }
-
-  /**
-   * Graph Traversal Source with method.
-   * @param {String} key
-   * @param {Object} value if not specified, the value with default to {@code true}
-   * @returns {GraphTraversalSource}
-   */
-  with_(key, value=undefined) {
-    const val = value === undefined ? true : value;
-    let optionsStrategy = this.bytecode.sourceInstructions.find(
-        i => i[0] === "withStrategies" && i[1] instanceof OptionsStrategy);
-    if (optionsStrategy === undefined) {
-      optionsStrategy = new OptionsStrategy({[key]: val});
-      return this.withStrategies(optionsStrategy);
-    } else {
-      optionsStrategy[1].configuration[key] = val;
-      return new this.graphTraversalSourceClass(this.graph, new TraversalStrategies(this.traversalStrategies),
-          this.bytecode, this.graphTraversalSourceClass, this.graphTraversalClass);
-    }
-  }
-
-  /**
-   * Returns the string representation of the GraphTraversalSource.
-   * @returns {string}
-   */
-  toString() {
-    return 'graphtraversalsource[' + this.graph.toString() + ']';
-  }
-  <% sourceStepMethods.each{ method -> %>
-  /**
-   * Graph Traversal Source <%= method %> method.
-   * @param {...Object} args
-   * @returns {GraphTraversalSource}
-   */
-  <%= toJs.call(method) %>(...args) {
-    const b = new Bytecode(this.bytecode).addSource('<%= method %>', args);
-    return new this.graphTraversalSourceClass(this.graph, new TraversalStrategies(this.traversalStrategies), b, this.graphTraversalSourceClass, this.graphTraversalClass);
-  }
-  <%
-  }
-  sourceSpawnMethods.each{ method -> %>
-  /**
-   * <%= method %> GraphTraversalSource step method.
-   * @param {...Object} args
-   * @returns {GraphTraversal}
-   */
-  <%= toJs.call(method) %>(...args) {
-    const b = new Bytecode(this.bytecode).addStep('<%= method %>', args);
-    return new this.graphTraversalClass(this.graph, new TraversalStrategies(this.traversalStrategies), b);
-  }
-  <% } %>
-}
-
-/**
- * Represents a graph traversal.
- */
-class GraphTraversal extends Traversal {
-  constructor(graph, traversalStrategies, bytecode) {
-    super(graph, traversalStrategies, bytecode);
-  }
-
-  /**
-   * Copy a traversal so as to reset and re-use it.
-   */
-  clone() {
-    return new GraphTraversal(this.graph, this.traversalStrategies, this.getBytecode());
-  }
-
-  <% graphStepMethods.each{ method -> %>
-  /**
-   * Graph traversal <%= method %> method.
-   * @param {...Object} args
-   * @returns {GraphTraversal}
-   */
-  <%= toJs.call(method) %>(...args) {
-    this.bytecode.addStep('<%= method %>', args);
-    return this;
-  }
-  <% } %>
-}
-
-function callOnEmptyTraversal(fnName, args) {
-  const g = new GraphTraversal(null, null, new Bytecode());
-  return g[fnName].apply(g, args);
-}
-
-/**
- * Contains the static method definitions
- * @type {Object}
- */
-const statics = {<% anonStepMethods.eachWithIndex { method, i -> %>
-  <%= toJs.call(method) %>: (...args) => callOnEmptyTraversal('<%= toJs.call(method) %>', args)<%= i < anonStepMethods.size() - 1 ? "," : ""%><% } %>
-};
-
-module.exports = {
-  GraphTraversal,
-  GraphTraversalSource,
-  statics
-};
\ No newline at end of file
diff --git a/gremlin-javascript/glv/PackageJson.template b/gremlin-javascript/glv/PackageJson.template
deleted file mode 100644
index 4089dc2..0000000
--- a/gremlin-javascript/glv/PackageJson.template
+++ /dev/null
@@ -1,62 +0,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.
-*/
-%>{
-  "name": "gremlin",
-  "version": "<%= version %>",
-  "description": "JavaScript Gremlin Language Variant",
-  "author": "Apache TinkerPop team",
-  "keywords": [
-    "graph",
-    "gremlin",
-    "tinkerpop",
-    "connection",
-    "glv",
-    "driver",
-    "graphdb"
-  ],
-  "license": "Apache-2.0",
-  "dependencies": {
-    "ws": "^6.2.1"
-  },
-  "devDependencies": {
-    "chai": "~4.1.2",
-    "cucumber": "~4.2.1",
-    "grunt": "~1.0.4",
-    "grunt-cli": "~1.3.2",
-    "grunt-jsdoc": "~2.3.1",
-    "mocha": "~5.2.0"
-  },
-  "repository": {
-    "type": "git",
-    "url": "https://github.com/apache/tinkerpop.git"
-  },
-  "homepage": "https://tinkerpop.apache.org/",
-  "bugs": {
-    "url": "https://issues.apache.org/jira/browse/TINKERPOP"
-  },
-  "scripts": {
-    "test": "./node_modules/mocha/bin/mocha test/unit test/integration -t 5000",
-    "features": "./node_modules/.bin/cucumber-js --require test/cucumber ../../../../../gremlin-test/features/",
-    "unit-test": "./node_modules/mocha/bin/mocha test/unit"
-  },
-  "engines": {
-    "node": ">=6"
-  }
-}
\ No newline at end of file
diff --git a/gremlin-javascript/glv/TraversalSource.template b/gremlin-javascript/glv/TraversalSource.template
deleted file mode 100644
index bf9a428..0000000
--- a/gremlin-javascript/glv/TraversalSource.template
+++ /dev/null
@@ -1,326 +0,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.
- */
-
-/**
- * @author Jorge Bay Gondra
- */
-'use strict';
-
-const utils = require('../utils');
-const itemDone = Object.freeze({ value: null, done: true });
-const asyncIteratorSymbol = Symbol.asyncIterator || Symbol('@@asyncIterator');
-
-class Traversal {
-  constructor(graph, traversalStrategies, bytecode) {
-    this.graph = graph;
-    this.traversalStrategies = traversalStrategies;
-    this.bytecode = bytecode;
-    /** @type {Array<Traverser>} */
-    this.traversers = null;
-    this.sideEffects = null;
-    this._traversalStrategiesPromise = null;
-    this._traversersIteratorIndex = 0;
-  }
-
-  /**
-   * Async iterable method implementation.
-   */
-  [asyncIteratorSymbol]() {
-    return this;
-  }
-
-  /** @returns {Bytecode} */
-  getBytecode() {
-    return this.bytecode;
-  }
-
-  /**
-   * Returns an Array containing the traverser objects.
-   * @returns {Promise.<Array>}
-   */
-  toList() {
-    return this._applyStrategies().then(() => {
-      const result = [];
-      let it;
-      while ((it = this._getNext()) && !it.done) {
-        result.push(it.value);
-      }
-      return result;
-    });
-  };
-
-  /**
-   * Determines if there are any more items to iterate from the traversal.
-   * @returns {Promise.<boolean>}
-   */
-   hasNext() {
-     return this._applyStrategies().then(() => {
-       return this.traversers && this.traversers.length > 0 &&
-              this._traversersIteratorIndex < this.traversers.length &&
-              this.traversers[this._traversersIteratorIndex].bulk > 0;
-     });
-   }
-
-  /**
-   * Iterates all Traverser instances in the traversal.
-   * @returns {Promise}
-   */
-  iterate() {
-    this.bytecode.addStep('none');
-    return this._applyStrategies().then(() => {
-      let it;
-      while ((it = this._getNext()) && !it.done) {
-      }
-    });
-  }
-
-  /**
-   * Async iterator method implementation.
-   * Returns a promise containing an iterator item.
-   * @returns {Promise.<{value, done}>}
-   */
-  next() {
-    return this._applyStrategies().then(() => this._getNext());
-  }
-
-  /**
-   * Synchronous iterator of traversers including
-   * @private
-   */
-  _getNext() {
-    while (this.traversers && this._traversersIteratorIndex < this.traversers.length) {
-      let traverser = this.traversers[this._traversersIteratorIndex];
-      if (traverser.bulk > 0) {
-        traverser.bulk--;
-        return { value: traverser.object, done: false };
-      }
-      this._traversersIteratorIndex++;
-    }
-    return itemDone;
-  }
-
-  _applyStrategies() {
-    if (this._traversalStrategiesPromise) {
-      // Apply strategies only once
-      return this._traversalStrategiesPromise;
-    }
-    return this._traversalStrategiesPromise = this.traversalStrategies.applyStrategies(this);
-  }
-
-  /**
-   * Returns step instructions during JSON serialization
-   * @returns {Array}
-   */
-  toJSON(){
-    return this.bytecode.stepInstructions;
-  }
-
-  /**
-   * Returns the Bytecode JSON representation of the traversal
-   * @returns {String}
-   */
-  toString() {
-    return this.bytecode.toString();
-  };
-}
-
-<% tokens.each { k,v -> %>
-class <%= k %> {
-<% v.each {a,b -> %>
- static get <%= a %>() {
-   return "<%= b %>"
- }
-<% } %>}
-<% } %>
-
-class P {
-  /**
-   * Represents an operation.
-   * @constructor
-   */
-  constructor(operator, value, other) {
-    this.operator = operator;
-    this.value = value;
-    this.other = other;
-  }
-
-  /**
-   * Returns the string representation of the instance.
-   * @returns {string}
-   */
-  toString() {
-    function formatValue(value){
-      if (Array.isArray(value)) {
-        let acc = [];
-        for (const item of value) {
-          acc.push(formatValue(item));
-        }
-        return acc;
-      }
-      if (value && typeof value === "string"){
-        return "'" + value + "'";
-      }
-      return value;
-    }
-
-    if (this.other === undefined || this.other === null) {
-      return this.operator + '(' + formatValue(this.value) + ')';
-    }
-    return this.operator + '(' + formatValue(this.value) + ', ' + formatValue(this.other) + ')';
-  }
-
-  and(arg) {
-    return new P('and', this, arg);
-  }
-
-  or(arg) {
-    return new P('or', this, arg);
-  }
-
-  static within(...args) {
-    if (args.length === 1 && Array.isArray(args[0])) {
-      return new P("within", args[0], null);
-    } else {
-      return new P("within", args, null);
-    }
-  }
-
-  static without(...args) {
-    if (args.length === 1 && Array.isArray(args[0])) {
-      return new P("without", args[0], null);
-    } else {
-      return new P("without", args, null);
-    }
-  }
-
-<% pmethods.findAll{!(it in ["within","without"])}.each{ method -> %>
-  /** @param {...Object} args */
-  static <%= toJs.call(method) %>(...args) {
-    return createP('<%= method %>', args);
-  }
-<% } %>
-}
-
-function createP(operator, args) {
-  args.unshift(null, operator);
-  return new (Function.prototype.bind.apply(P, args));
-}
-
-class TextP {
-  /**
-   * Represents an operation.
-   * @constructor
-   */
-  constructor(operator, value, other) {
-    this.operator = operator;
-    this.value = value;
-    this.other = other;
-  }
-
-  /**
-   * Returns the string representation of the instance.
-   * @returns {string}
-   */
-  toString() {
-    function formatValue(value){
-      if (value && typeof value === "string"){
-        return "'" + value + "'";
-      }
-      return value;
-    }
-
-    if (this.other === undefined) {
-      return this.operator + '(' + formatValue(this.value) + ')';
-    }
-    return this.operator + '(' + formatValue(this.value) + ', ' + formatValue(this.other) + ')';
-  }
-
-  and(arg) {
-    return new P('and', this, arg);
-  }
-
-  or(arg) {
-    return new P('or', this, arg);
-  }
-<% tpmethods.each{ method -> %>
-  /** @param {...Object} args */
-  static <%= toJs.call(method) %>(...args) {
-    return createTextP('<%= method %>', args);
-  }
-<% } %>
-}
-
-function createTextP(operator, args) {
-  args.unshift(null, operator);
-  return new (Function.prototype.bind.apply(TextP, args));
-}
-
-class Traverser {
-  constructor(object, bulk) {
-    this.object = object;
-    this.bulk = bulk || 1;
-  }
-}
-
-class TraversalSideEffects {
-
-}
-
-const withOptions = {
-  <%= withOptions.collect { it.name + ": " + it.value }.join(",\n  ")%>
-};
-
-function toEnum(typeName, keys) {
-  const result = {};
-  keys.split(' ').forEach(k => {
-    let jsKey = k;
-    if (jsKey === jsKey.toUpperCase()) {
-      jsKey = jsKey.toLowerCase();
-    }
-    result[jsKey] = new EnumValue(typeName, k);
-  });
-  return result;
-}
-
-class EnumValue {
-  constructor(typeName, elementName) {
-    this.typeName = typeName;
-    this.elementName = elementName;
-  }
-
-  toString() {
-    return this.elementName;
-  }
-}
-
-module.exports = {
-  EnumValue,
-  P,
-  TextP,
-  withOptions,
-  IO,
-  Traversal,
-  TraversalSideEffects,
-  Traverser<%
-enums.each{ enumClass ->
-    out.print ",\n  " + decapitalize.call(enumClass.simpleName) + ": toEnum('" + enumClass.simpleName + "', '" +
-        enumClass.getEnumConstants().sort { a, b -> a.name() <=> b.name() }.collect { toJs.call(it.name()) }.join(' ') + "')"
-}
-%>
-};
diff --git a/gremlin-javascript/glv/generate.groovy b/gremlin-javascript/glv/generate.groovy
deleted file mode 100644
index 2d3e1a1..0000000
--- a/gremlin-javascript/glv/generate.groovy
+++ /dev/null
@@ -1,135 +0,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.
- */
-
-
-import groovy.text.GStringTemplateEngine
-import org.apache.tinkerpop.gremlin.jsr223.CoreImports
-import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.ConnectedComponent
-import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.PageRank
-import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.PeerPressure
-import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.ShortestPath
-import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource
-import org.apache.tinkerpop.gremlin.process.traversal.P
-import org.apache.tinkerpop.gremlin.process.traversal.TextP
-import org.apache.tinkerpop.gremlin.process.traversal.IO
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.WithOptions
-import java.lang.reflect.Modifier
-
-def toJsMap = ["in": "in_",
-               "from": "from_",
-               "with": "with_"]
-
-def toJs = { symbol -> toJsMap.getOrDefault(symbol, symbol) }
-
-def toJSValue = { type, value ->
-  type == String.class && value != null ? ('"' + value + '"') : value
-}
-
-def decapitalize = {
-    String string = it;
-    if (string == null || string.length() == 0) {
-        return string;
-    }
-    def c = string.toCharArray();
-    c[0] = Character.toLowerCase(c[0]);
-    return new String(c);
-}
-
-def determineVersion = {
-    def env = System.getenv()
-    def mavenVersion = env.containsKey("TP_RELEASE_VERSION") ? env.get("JS_RELEASE_VERSION") : project.version
-    return mavenVersion.replace("-SNAPSHOT", "-alpha1")
-}
-
-def gatherTokensFrom = { tokenClasses ->
-    def m = [:]
-    tokenClasses.each { tc -> m << [(tc.simpleName) : tc.getFields().sort{ a, b -> a.name <=> b.name }.collectEntries{ f -> [(f.name) : f.get(null)]}]}
-    return m
-}
-
-def binding = ["enums": CoreImports.getClassImports()
-        .findAll { Enum.class.isAssignableFrom(it) }
-        .sort { a, b -> a.getSimpleName() <=> b.getSimpleName() },
-               "pmethods": P.class.getMethods().
-                       findAll { Modifier.isStatic(it.getModifiers()) }.
-                       findAll { P.class.isAssignableFrom(it.returnType) }.
-                       collect { it.name }.
-                       unique().
-                       sort { a, b -> a <=> b },
-               "tpmethods": TextP.class.getMethods().
-                       findAll { Modifier.isStatic(it.getModifiers()) }.
-                       findAll { TextP.class.isAssignableFrom(it.returnType) }.
-                       collect { it.name }.
-                       unique().
-                       sort { a, b -> a <=> b },
-               "sourceStepMethods": GraphTraversalSource.getMethods(). // SOURCE STEPS
-                       findAll { (GraphTraversalSource.class == it.returnType) }.
-                       findAll {
-                           !it.name.equals("clone") &&
-                                   // Use hardcoded name to be for forward-compatibility
-                                   it.name != "withBindings" &&
-                                   it.name != TraversalSource.Symbols.with &&
-                                   it.name != TraversalSource.Symbols.withRemote &&
-                                   it.name != TraversalSource.Symbols.withComputer
-                       }.
-                       collect { it.name }.
-                       unique().
-                       sort { a, b -> a <=> b },
-               "sourceSpawnMethods": GraphTraversalSource.getMethods(). // SPAWN STEPS
-                       findAll { (GraphTraversal.class == it.returnType) }.
-                       collect { it.name }.
-                       unique().
-                       sort { a, b -> a <=> b },
-               "graphStepMethods": GraphTraversal.getMethods().
-                       findAll { (GraphTraversal.class == it.returnType) }.
-                       findAll { !it.name.equals("clone") && !it.name.equals("iterate") }.
-                       collect { it.name }.
-                       unique().
-                       sort { a, b -> a <=> b },
-               "anonStepMethods": __.class.getMethods().
-                       findAll { (GraphTraversal.class == it.returnType) }.
-                       findAll { Modifier.isStatic(it.getModifiers()) }.
-                       findAll { !it.name.equals("__") && it.name != "start" }.
-                       collect { it.name }.
-                       unique().
-                       sort { a, b -> a <=> b },
-               "tokens": gatherTokensFrom([IO, ConnectedComponent, ShortestPath, PageRank, PeerPressure]),
-               "toJs": toJs,
-               "version": determineVersion(),
-               "decapitalize": decapitalize,
-               "withOptions": WithOptions.getDeclaredFields().
-                        collect {["name": it.name, "value": toJSValue(it.type, it.get(null))]}]
-
-def engine = new GStringTemplateEngine()
-def graphTraversalTemplate = engine.createTemplate(new File("${project.basedir}/glv/GraphTraversalSource.template"))
-        .make(binding)
-def graphTraversalFile =
-        new File("${project.basedir}/src/main/javascript/gremlin-javascript/lib/process/graph-traversal.js")
-graphTraversalFile.newWriter().withWriter{ it << graphTraversalTemplate }
-
-def traversalTemplate = engine.createTemplate(new File("${project.basedir}/glv/TraversalSource.template")).make(binding)
-def traversalFile = new File("${project.basedir}/src/main/javascript/gremlin-javascript/lib/process/traversal.js")
-traversalFile.newWriter().withWriter{ it << traversalTemplate }
-
-def packageJsonTemplate = engine.createTemplate(new File("${project.basedir}/glv/PackageJson.template")).make(binding)
-def packageJsonFile = new File("${project.basedir}/src/main/javascript/gremlin-javascript/package.json")
-packageJsonFile.newWriter().withWriter{ it << packageJsonTemplate }
diff --git a/gremlin-javascript/pom.xml b/gremlin-javascript/pom.xml
index 2244fcf..5eb2f06 100644
--- a/gremlin-javascript/pom.xml
+++ b/gremlin-javascript/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.apache.tinkerpop</groupId>
         <artifactId>tinkerpop</artifactId>
-        <version>3.4.12-SNAPSHOT</version>
+        <version>3.5.1-SNAPSHOT</version>
     </parent>
     <artifactId>gremlin-javascript</artifactId>
     <name>Apache TinkerPop :: Gremlin Javascript</name>
@@ -29,10 +29,21 @@
         <maven.test.skip>false</maven.test.skip>
         <skipTests>${maven.test.skip}</skipTests>
         <gremlin.server.dir>${project.parent.basedir}/gremlin-server</gremlin.server.dir>
+        <npm.version>6.14.6</npm.version>
+        <node.version>v10.22.0</node.version>
     </properties>
     <build>
         <directory>${basedir}/target</directory>
         <finalName>${project.artifactId}-${project.version}</finalName>
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>com.github.eirslett</groupId>
+                    <artifactId>frontend-maven-plugin</artifactId>
+                    <version>1.10.0</version>
+                </plugin>
+            </plugins>
+        </pluginManagement>
         <plugins>
             <plugin>
                 <!--
@@ -49,6 +60,11 @@
                         <version>${project.version}</version>
                     </dependency>
                     <dependency>
+                        <groupId>org.apache.tinkerpop</groupId>
+                        <artifactId>gremlin-test</artifactId>
+                        <version>${project.version}</version>
+                    </dependency>
+                    <dependency>
                         <groupId>log4j</groupId>
                         <artifactId>log4j</artifactId>
                         <version>${log4j.version}</version>
@@ -64,7 +80,7 @@
                 </dependencies>
                 <executions>
                     <execution>
-                        <id>generate-javascript</id>
+                        <id>generate-radish-support</id>
                         <phase>generate-sources</phase>
                         <goals>
                             <goal>execute</goal>
@@ -73,15 +89,28 @@
                             <properties>
                                 <property>
                                     <name>projectBaseDir</name>
-                                    <value>${project.basedir}</value>
-                                </property>
-                                <property>
-                                    <name>projectVersion</name>
-                                    <value>${project.version}</value>
+                                    <value>${project.basedir}/../</value>
                                 </property>
                             </properties>
                             <scripts>
-                                <script>${project.basedir}/glv/generate.groovy</script>
+                                <script>${project.basedir}/build/generate.groovy</script>
+                            </scripts>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>update-version</id>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>execute</goal>
+                        </goals>
+                        <configuration>
+                            <scripts>
+                                <script>
+def mavenVersion = "${project.version}"
+def versionForJs = mavenVersion.replace("-SNAPSHOT", "-alpha1")
+def file = new File("${project.basedir}/src/main/javascript/gremlin-javascript/package.json")
+file.write(file.getText("UTF-8").replaceFirst(/"version": "(.*)",/, "\"version\": \"" + versionForJs + "\","))
+                                </script>
                             </scripts>
                         </configuration>
                     </execution>
@@ -98,10 +127,6 @@
                                     <value>${skipTests}</value>
                                 </property>
                                 <property>
-                                    <name>python</name>
-                                    <value>false</value>
-                                </property>
-                                <property>
                                     <name>gremlinServerDir</name>
                                     <value>${gremlin.server.dir}</value>
                                 </property>
@@ -161,7 +186,6 @@
             <plugin>
                 <groupId>com.github.eirslett</groupId>
                 <artifactId>frontend-maven-plugin</artifactId>
-                <version>1.7.6</version>
                 <executions>
                     <execution>
                         <id>install node and npm</id>
@@ -217,7 +241,8 @@
                 </executions>
                 <configuration>
                     <workingDirectory>src/main/javascript/gremlin-javascript</workingDirectory>
-                    <nodeVersion>v6.12.3</nodeVersion>
+                    <nodeVersion>${node.version}</nodeVersion>
+                    <npmVersion>${npm.version}</npmVersion>
                 </configuration>
             </plugin>
             <!--
@@ -273,7 +298,6 @@
                     <plugin>
                         <groupId>com.github.eirslett</groupId>
                         <artifactId>frontend-maven-plugin</artifactId>
-                        <version>1.4</version>
                         <executions>
                             <execution>
                                 <id>npm publish</id>
@@ -294,7 +318,8 @@
                             -->
                             <skip>false</skip>
                             <workingDirectory>src/main/javascript/gremlin-javascript</workingDirectory>
-                            <nodeVersion>v6.12.3</nodeVersion>
+                            <nodeVersion>${node.version}</nodeVersion>
+                            <npmVersion>${npm.version}</npmVersion>
                         </configuration>
                     </plugin>
                 </plugins>
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/client.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/client.js
index b938963..4429c37 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/client.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/client.js
@@ -66,6 +66,14 @@
   }
 
   /**
+   * Returns true if the underlying connection is open
+   * @returns {Boolean}
+   */
+  get isOpen() {
+    return this._connection.isOpen;
+  }
+
+  /**
    * Send a request to the Gremlin Server, can send a script or bytecode steps.
    * @param {Bytecode|string} message The bytecode or script to send
    * @param {Object} [bindings] The script bindings, if any.
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/driver-remote-connection.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/driver-remote-connection.js
index 62cbdb5..f7d626d 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/driver-remote-connection.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/driver-remote-connection.js
@@ -59,6 +59,10 @@
     return this._client.open();
   }
 
+  get isOpen() {
+    return this._client.isOpen;
+  }
+
   /** @override */
   submit(bytecode) {
     let optionsStrategy = bytecode.sourceInstructions.find(
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/remote-connection.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/remote-connection.js
index cc4c4d2..d53f320 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/remote-connection.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/remote-connection.js
@@ -43,6 +43,14 @@
   }
 
   /**
+   * Returns true if connection is open
+   * @returns {Boolean}
+   */
+  get isOpen() {
+    throw new Error('isOpen() must be implemented');
+  }
+
+  /**
    * Submits the <code>Bytecode</code> provided and returns a <code>RemoteTraversal</code>.
    * @abstract
    * @param {Bytecode} bytecode
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/bytecode.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/bytecode.js
index 2d95e6d..03b6f5c 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/bytecode.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/bytecode.js
@@ -22,6 +22,8 @@
  */
 'use strict';
 
+const { Traversal } = require('./traversal');
+
 class Bytecode {
   /**
    * Creates a new instance of Bytecode
@@ -76,7 +78,11 @@
     const instruction = new Array(length);
     instruction[0] = name;
     for (let i = 1; i < length; i++) {
-      instruction[i] = values[i - 1];
+      const val = values[i - 1];
+      if (val instanceof Traversal && val.graph != null)
+        throw new Error("The child traversal of ${val} was not spawned anonymously - use " +
+            "the __ class rather than a TraversalSource to construct the child traversal");
+      instruction[i] = val;
     }
     return instruction;
   }
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal.js
index c1c3a4a..f72c3f9 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal.js
@@ -497,7 +497,7 @@
   graphSONVersion: toEnum('GraphSONVersion', 'V1_0 V2_0 V3_0'),
   gryoVersion: toEnum('GryoVersion', 'V1_0 V3_0'),
   operator: toEnum('Operator', 'addAll and assign div max min minus mult or sum sumLong'),
-  order: toEnum('Order', 'asc decr desc incr shuffle'),
+  order: toEnum('Order', 'asc desc shuffle'),
   pick: toEnum('Pick', 'any none'),
   pop: toEnum('Pop', 'all first last mixed'),
   scope: toEnum('Scope', 'global local'),
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/package.json b/gremlin-javascript/src/main/javascript/gremlin-javascript/package.json
index 27c2ec6..fc39de3 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/package.json
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/package.json
@@ -1,6 +1,6 @@
 {
   "name": "gremlin",
-  "version": "3.4.12-alpha1",
+  "version": "3.5.1-alpha1",
   "description": "JavaScript Gremlin Language Variant",
   "author": "Apache TinkerPop team",
   "keywords": [
@@ -19,9 +19,9 @@
   "devDependencies": {
     "chai": "~4.1.2",
     "cucumber": "~4.2.1",
-    "grunt": "~1.0.4",
+    "grunt": "~1.2.0",
     "grunt-cli": "~1.3.2",
-    "grunt-jsdoc": "~2.3.1",
+    "grunt-jsdoc": "~2.4.1",
     "mocha": "~5.2.0"
   },
   "repository": {
@@ -38,6 +38,6 @@
     "unit-test": "./node_modules/mocha/bin/mocha test/unit"
   },
   "engines": {
-    "node": ">=6"
+    "node": ">=10"
   }
-}
\ No newline at end of file
+}
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js
index 787396b..07be9f9 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js
@@ -23,9 +23,9 @@
 'use strict';
 
 const {Given, Then, When} = require('cucumber');
-const vm = require('vm');
 const expect = require('chai').expect;
 const util = require('util');
+const gremlin = require('./gremlin').gremlin;
 const graphModule = require('../../lib/structure/graph');
 const graphTraversalModule = require('../../lib/process/graph-traversal');
 const traversalModule = require('../../lib/process/traversal');
@@ -59,6 +59,7 @@
 ].map(x => [ new RegExp('^' + x[0] + '$'), x[1] ]);
 
 const ignoreReason = {
+  nullKeysInMapNotSupportedWell: "Javascript does not nicely support 'null' as a key in Map instances",
   setNotSupported: "There is no Set support in gremlin-javascript",
   needsFurtherInvestigation: '',
 };
@@ -67,6 +68,7 @@
   // An associative array containing the scenario name as key, for example:
   'g_withSideEffectXa_setX_V_both_name_storeXaX_capXaX': new IgnoreError(ignoreReason.setNotSupported),
   'g_withSideEffectXa_setX_V_both_name_aggregateXlocal_aX_capXaX': new IgnoreError(ignoreReason.setNotSupported),
+  'g_V_group_byXageX': new IgnoreError(ignoreReason.nullKeysInMapNotSupportedWell),
   'g_V_shortestPath_edgesIncluded': new IgnoreError(ignoreReason.needsFurtherInvestigation),
   'g_V_shortestPath_edgesIncluded_edgesXoutEX': new IgnoreError(ignoreReason.needsFurtherInvestigation)
 };
@@ -84,14 +86,18 @@
 });
 
 Given('the graph initializer of', function (traversalText) {
-  const traversal = vm.runInNewContext(translate(traversalText), getSandbox(this.g, this.parameters));
+  const p = Object.assign({}, this.parameters);
+  p.g = this.g;
+  const traversal = gremlin[this.scenario].shift()(p);
   return traversal.toList();
 });
 
 Given('an unsupported test', () => {});
 
 Given('the traversal of', function (traversalText) {
-  this.traversal = vm.runInNewContext(translate(traversalText), getSandbox(this.g, this.parameters));
+  const p = Object.assign({}, this.parameters);
+  p.g = this.g;
+  this.traversal = gremlin[this.scenario].shift()(p);
 });
 
 Given(/^using the parameter (.+) of P\.(.+)\("(.+)"\)$/, function (paramName, pval, stringValue) {
@@ -153,7 +159,9 @@
 });
 
 Then(/^the graph should return (\d+) for count of "(.+)"$/, function (stringCount, traversalText) {
-  const traversal = vm.runInNewContext(translate(traversalText), getSandbox(this.g, this.parameters));
+  const p = Object.assign({}, this.parameters);
+  p.g = this.g;
+  const traversal = gremlin[this.scenario].shift()(p);
   return traversal.toList().then(list => {
     expect(list).to.have.lengthOf(parseInt(stringCount, 10));
   });
@@ -209,25 +217,15 @@
   return sandbox;
 }
 
-function translate(traversalText) {
-  // clean up trailing period/spaces so that it's easier to match newline with() to convert to with_() below
-  traversalText = traversalText.replace(/\)\.\s*/g, ').');
-  // Remove escaped chars
-  traversalText = traversalText.replace(/\\"/g, '"');
-  // Replace long suffix with Long instance
-  traversalText = traversalText.replace(/\b(\d+)l\b/gi, 'toLong($1)');
-  // Change according to naming convention
-  traversalText = traversalText.replace(/\.in\(/g, '.in_(');
-  traversalText = traversalText.replace(/\.from\(/g, '.from_(');
-  traversalText = traversalText.replace(/\.with\(/g, '.with_(');
-  return traversalText;
-}
-
 function parseRow(row) {
   return parseValue.call(this, row[0]);
 }
 
 function parseValue(stringValue) {
+
+  if(stringValue === "null")
+    return null;
+
   let extractedValue = null;
   let parser = null;
   for (let item of parsers) {
@@ -239,6 +237,7 @@
       break;
     }
   }
+
   return parser !== null ? parser.call(this, extractedValue) : stringValue;
 }
 
@@ -284,7 +283,7 @@
 }
 
 function toDirection(value) {
-    return direction[value.toLowerCase()];
+  return direction[value.toLowerCase()];
 }
 
 function toArray(stringList) {
@@ -299,6 +298,9 @@
 }
 
 function parseMapValue(value) {
+  if (value === null)
+    return null;
+
   if (typeof value === 'string') {
     return parseValue.call(this, value);
   }
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
new file mode 100644
index 0000000..6fab554
--- /dev/null
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
@@ -0,0 +1,684 @@
+/*
+* 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.
+*/
+
+
+
+//********************************************************************************
+//* Do NOT edit this file directly - generated by build/generate.groovy
+//********************************************************************************
+
+
+const graphTraversalModule = require('../../lib/process/graph-traversal');
+const traversalModule = require('../../lib/process/traversal');
+const { TraversalStrategies, VertexProgramStrategy, OptionsStrategy } = require('../../lib/process/traversal-strategy');
+const __ = graphTraversalModule.statics;
+const Barrier = traversalModule.barrier
+const Cardinality = traversalModule.cardinality
+const Column = traversalModule.column
+const Direction = {
+    BOTH: traversalModule.direction.both,
+    IN: traversalModule.direction.in,
+    OUT: traversalModule.direction.out
+};
+const P = traversalModule.P;
+const Pick = traversalModule.pick
+const Pop = traversalModule.pop
+const Order = traversalModule.order
+const Operator = traversalModule.operator
+const Scope = traversalModule.scope
+const T = traversalModule.t
+const TextP = traversalModule.TextP
+const WithOptions = traversalModule.withOptions
+
+const gremlins = {
+    g_V_branchXlabel_eq_person__a_bX_optionXa__ageX_optionXb__langX_optionXb__nameX: [function({g, l1}) { return g.V().branch(l1).option("a",__.values("age")).option("b",__.values("lang")).option("b",__.values("name")) }], 
+    g_V_branchXlabel_isXpersonX_countX_optionX1__ageX_optionX0__langX_optionX0__nameX: [function({g, xx1, xx2}) { return g.V().branch(__.label().is("person").count()).option(xx1,__.values("age")).option(xx2,__.values("lang")).option(xx2,__.values("name")) }], 
+    g_V_branchXlabel_isXpersonX_countX_optionX1__ageX_optionX0__langX_optionX0__nameX_optionXany__labelX: [function({g, xx1, xx2}) { return g.V().branch(__.label().is("person").count()).option(xx1,__.values("age")).option(xx2,__.values("lang")).option(xx2,__.values("name")).option(Pick.any,__.label()) }], 
+    g_V_branchXageX_optionXltX30X__youngX_optionXgtX30X__oldX_optionXnone__on_the_edgeX: [function({g}) { return g.V().hasLabel("person").branch(__.values("age")).option(P.lt(30),__.constant("young")).option(P.gt(30),__.constant("old")).option(Pick.none,__.constant("on the edge")) }], 
+    g_V_branchXidentityX_optionXhasLabelXsoftwareX__inXcreatedX_name_order_foldX_optionXhasXname_vadasX__ageX_optionXneqX123X__bothE_countX: [function({g}) { return g.V().branch(__.identity()).option(__.hasLabel("software"),__.in_("created").values("name").order().fold()).option(__.has("name","vadas"),__.values("age")).option(P.neq(123),__.bothE().count()) }], 
+    g_V_chooseXout_countX_optionX2L_nameX_optionX3L_ageX: [function({g, xx1, xx2}) { return g.V().choose(__.out().count()).option(xx1,__.values("name")).option(xx2,__.values("age")) }], 
+    g_V_chooseXlabel_eqXpersonX__outXknowsX__inXcreatedXX_name: [function({g, pred1}) { return g.V().choose(pred1,__.out("knows"),__.in_("created")).values("name") }], 
+    g_V_chooseXhasLabelXpersonX_and_outXcreatedX__outXknowsX__identityX_name: [function({g}) { return g.V().choose(__.hasLabel("person").and().out("created"),__.out("knows"),__.identity()).values("name") }], 
+    g_V_chooseXlabelX_optionXblah__outXknowsXX_optionXbleep__outXcreatedXX_optionXnone__identityX_name: [function({g}) { return g.V().choose(__.label()).option("blah",__.out("knows")).option("bleep",__.out("created")).option(Pick.none,__.identity()).values("name") }], 
+    g_V_chooseXoutXknowsX_count_isXgtX0XX__outXknowsXX_name: [function({g}) { return g.V().choose(__.out("knows").count().is(P.gt(0)),__.out("knows")).values("name") }], 
+    g_V_hasLabelXpersonX_asXp1X_chooseXoutEXknowsX__outXknowsXX_asXp2X_selectXp1_p2X_byXnameX: [function({g}) { return g.V().hasLabel("person").as("p1").choose(__.outE("knows"),__.out("knows")).as("p2").select("p1","p2").by("name") }], 
+    g_V_hasLabelXpersonX_chooseXageX__optionX27L__constantXyoungXX_optionXnone__constantXoldXX_groupCount: [function({g, xx1}) { return g.V().hasLabel("person").choose(__.values("age")).option(xx1,__.constant("young")).option(Pick.none,__.constant("old")).groupCount() }], 
+    g_injectX1X_chooseXisX1X__constantX10Xfold__foldX: [function({g, xx1, xx2}) { return g.inject(xx2).choose(__.is(xx2),__.constant(xx1).fold(),__.fold()) }], 
+    g_injectX2X_chooseXisX1X__constantX10Xfold__foldX: [function({g, xx1, xx3, xx2}) { return g.inject(xx3).choose(__.is(xx2),__.constant(xx1).fold(),__.fold()) }], 
+    g_V_localXpropertiesXlocationX_order_byXvalueX_limitX2XX_value: [function({g}) { return g.V().local(__.properties("location").order().by(T.value,Order.asc).range(0,2)).value() }], 
+    g_V_hasXlabel_personX_asXaX_localXoutXcreatedX_asXbXX_selectXa_bX_byXnameX_byXidX: [function({g}) { return g.V().has(T.label,"person").as("a").local(__.out("created").as("b")).select("a","b").by("name").by(T.id) }], 
+    g_V_localXoutE_countX: [function({g}) { return g.V().local(__.outE().count()) }], 
+    g_VX1X_localXoutEXknowsX_limitX1XX_inV_name: [function({g, vid1}) { return g.V(vid1).local(__.outE("knows").limit(1)).inV().values("name") }], 
+    g_V_localXbothEXcreatedX_limitX1XX_otherV_name: [function({g}) { return g.V().local(__.bothE("created").limit(1)).otherV().values("name") }], 
+    g_VX4X_localXbothEX1_createdX_limitX1XX: [function({g, vid4}) { return g.V(vid4).local(__.bothE("created").limit(1)) }], 
+    g_VX4X_localXbothEXknows_createdX_limitX1XX: [function({g, vid4}) { return g.V(vid4).local(__.bothE("knows","created").limit(1)) }], 
+    g_VX4X_localXbothE_limitX1XX_otherV_name: [function({g, vid4}) { return g.V(vid4).local(__.bothE().limit(1)).otherV().values("name") }], 
+    g_VX4X_localXbothE_limitX2XX_otherV_name: [function({g, vid4}) { return g.V(vid4).local(__.bothE().limit(2)).otherV().values("name") }], 
+    g_V_localXinEXknowsX_limitX2XX_outV_name: [function({g}) { return g.V().local(__.inE("knows").limit(2)).outV().values("name") }], 
+    g_V_localXmatchXproject__created_person__person_name_nameX_selectXname_projectX_by_byXnameX: [function({g}) { return g.V().local(__.match(__.as("project").in_("created").as("person"),__.as("person").values("name").as("name"))).select("name","project").by().by("name") }], 
+    g_VX2X_optionalXoutXknowsXX: [function({g, vid2}) { return g.V(vid2).optional(__.out("knows")) }], 
+    g_VX2X_optionalXinXknowsXX: [function({g, vid2}) { return g.V(vid2).optional(__.in_("knows")) }], 
+    g_V_hasLabelXpersonX_optionalXoutXknowsX_optionalXoutXcreatedXXX_path: [function({g}) { return g.V().hasLabel("person").optional(__.out("knows").optional(__.out("created"))).path() }], 
+    g_V_optionalXout_optionalXoutXX_path: [function({g}) { return g.V().optional(__.out().optional(__.out())).path() }], 
+    g_VX1X_optionalXaddVXdogXX_label: [function({g, vid1}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","java").as("ripple").addV("person").property(T.id,6).property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property(T.id,7).property("weight",0.5).addE("knows").from_("marko").to("josh").property(T.id,8).property("weight",1.0).addE("created").from_("marko").to("lop").property(T.id,9).property("weight",0.4).addE("created").from_("josh").to("ripple").property(T.id,10).property("weight",1.0).addE("created").from_("josh").to("lop").property(T.id,11).property("weight",0.4).addE("created").from_("peter").to("lop").property(T.id,12).property("weight",0.2) }, function({g, vid1}) { return g.V(vid1).optional(__.addV("dog")).label() }, function({g, vid1}) { return g.V() }], 
+    g_V_repeatXoutX_timesX2X_emit_path: [function({g}) { return g.V().repeat(__.out()).times(2).emit().path() }], 
+    g_V_repeatXoutX_timesX2X_repeatXinX_timesX2X_name: [function({g}) { return g.V().repeat(__.out()).times(2).repeat(__.in_()).times(2).values("name") }], 
+    g_V_repeatXoutX_timesX2X: [function({g}) { return g.V().repeat(__.out()).times(2) }], 
+    g_V_repeatXoutX_timesX2X_emit: [function({g}) { return g.V().repeat(__.out()).times(2).emit() }], 
+    g_VX1X_timesX2X_repeatXoutX_name: [function({g, vid1}) { return g.V(vid1).times(2).repeat(__.out()).values("name") }], 
+    g_V_emit_timesX2X_repeatXoutX_path: [function({g}) { return g.V().emit().times(2).repeat(__.out()).path() }], 
+    g_V_emit_repeatXoutX_timesX2X_path: [function({g}) { return g.V().emit().repeat(__.out()).times(2).path() }], 
+    g_VX1X_emitXhasXlabel_personXX_repeatXoutX_name: [function({g, vid1}) { return g.V(vid1).emit(__.has(T.label,"person")).repeat(__.out()).values("name") }], 
+    g_V_repeatXgroupCountXmX_byXnameX_outX_timesX2X_capXmX: [function({g}) { return g.V().repeat(__.groupCount("m").by("name").out()).times(2).cap("m") }], 
+    g_VX1X_repeatXgroupCountXmX_byXloopsX_outX_timesX3X_capXmX: [function({g, vid1}) { return g.V(vid1).repeat(__.groupCount("m").by(__.loops()).out()).times(3).cap("m") }], 
+    g_V_repeatXbothX_timesX10X_asXaX_out_asXbX_selectXa_bX: [function({g}) { return g.V().repeat(__.both()).times(10).as("a").out().as("b").select("a","b").count() }], 
+    g_VX1X_repeatXoutX_untilXoutE_count_isX0XX_name: [function({g, vid1}) { return g.V(vid1).repeat(__.out()).until(__.outE().count().is(0)).values("name") }], 
+    g_V_repeatXbothX_untilXname_eq_marko_or_loops_gt_1X_groupCount_byXnameX: [function({g, pred1}) { return g.V().repeat(__.both()).until(pred1).groupCount().by("name") }], 
+    g_V_hasXname_markoX_repeatXoutE_inV_simplePathX_untilXhasXname_rippleXX_path_byXnameX_byXlabelX: [function({g}) { return g.V().has("name","marko").repeat(__.outE().inV().simplePath()).until(__.has("name","ripple")).path().by("name").by(T.label) }], 
+    g_V_hasXloop_name_loopX_repeatXinX_timesX5X_path_by_name: [function({g}) { return g.V().has("loops","name","loop").repeat(__.in_()).times(5).path().by("name") }], 
+    g_V_repeatXout_repeatXoutX_timesX1XX_timesX1X_limitX1X_path_by_name: [function({g}) { return g.V().repeat(__.out().repeat(__.out()).times(1)).times(1).limit(1).path().by("name") }], 
+    g_V_repeatXoutXknowsXX_untilXrepeatXoutXcreatedXX_emitXhasXname_lopXXX_path_byXnameX: [function({g}) { return g.V().repeat(__.out("knows")).until(__.repeat(__.out("created")).emit(__.has("name","lop"))).path().by("name") }], 
+    g_V_repeatXrepeatXout_createdXX_untilXhasXname_rippleXXXemit_lang: [function({g}) { return g.V().repeat(__.repeat(__.out("created")).until(__.has("name","ripple"))).emit().values("lang") }], 
+    g_V_untilXconstantXtrueXX_repeatXrepeatXout_createdXX_untilXhasXname_rippleXXXemit_lang: [function({g}) { return g.V().until(__.constant(true)).repeat(__.repeat(__.out("created")).until(__.has("name","ripple"))).emit().values("lang") }], 
+    g_V_emit_repeatXa_outXknows_filterXloops_isX0XX_lang: [function({g}) { return g.V().emit().repeat("a",__.out("knows").filter(__.loops("a").is(0))).values("lang") }], 
+    g_VX3X_repeatXbothX_createdXX_untilXloops_is_40XXemit_repeatXin_knowsXX_emit_loopsXisX1Xdedup_values: [function({g, vid3}) { return g.V(vid3).repeat(__.both("created")).until(__.loops().is(40)).emit(__.repeat(__.in_("knows")).emit(__.loops().is(1))).dedup().values("name") }], 
+    g_VX1X_repeatXrepeatXunionXout_uses_out_traversesXX_whereXloops_isX0X_timesX1X_timeX2X_name: [function({g, vid1}) { return g.V(vid1).repeat(__.repeat(__.union(__.out("uses"),__.out("traverses")).where(__.loops().is(0))).times(1)).times(2).values("name") }], 
+    g_V_repeatXa_outXknows_repeatXb_outXcreatedX_filterXloops_isX0XX_emit_lang: [function({g}) { return g.V().repeat("a",__.out("knows").repeat("b",__.out("created").filter(__.loops("a").is(0))).emit()).emit().values("lang") }], 
+    g_VX6X_repeatXa_bothXcreatedX_simplePathX_emitXrepeatXb_bothXknowsXX_untilXloopsXbX_asXb_whereXloopsXaX_asXbX_hasXname_vadasXX_dedup_name: [function({g, vid6}) { return g.V(vid6).repeat("a",__.both("created").simplePath()).emit(__.repeat("b",__.both("knows")).until(__.loops("b").as("b").where(__.loops("a").as("b"))).has("name","vadas")).dedup().values("name") }], 
+    g_V_unionXout__inX_name: [function({g}) { return g.V().union(__.out(),__.in_()).values("name") }], 
+    g_VX1X_unionXrepeatXoutX_timesX2X__outX_name: [function({g, vid1}) { return g.V(vid1).union(__.repeat(__.out()).times(2),__.out()).values("name") }], 
+    g_V_chooseXlabel_is_person__unionX__out_lang__out_nameX__in_labelX: [function({g}) { return g.V().choose(__.label().is("person"),__.union(__.out().values("lang"),__.out().values("name")),__.in_().label()) }], 
+    g_V_chooseXlabel_is_person__unionX__out_lang__out_nameX__in_labelX_groupCount: [function({g}) { return g.V().choose(__.label().is("person"),__.union(__.out().values("lang"),__.out().values("name")),__.in_().label()).groupCount() }], 
+    g_V_unionXrepeatXunionXoutXcreatedX__inXcreatedXX_timesX2X__repeatXunionXinXcreatedX__outXcreatedXX_timesX2XX_label_groupCount: [function({g}) { return g.V().union(__.repeat(__.union(__.out("created"),__.in_("created"))).times(2),__.repeat(__.union(__.in_("created"),__.out("created"))).times(2)).label().groupCount() }], 
+    g_VX1_2X_unionXoutE_count__inE_count__outE_weight_sumX: [function({g, vid2, vid1}) { return g.V(vid1,vid2).union(__.outE().count(),__.inE().count(),__.outE().values("weight").sum()) }], 
+    g_VX1_2X_localXunionXoutE_count__inE_count__outE_weight_sumXX: [function({g, vid2, vid1}) { return g.V(vid1,vid2).local(__.union(__.outE().count(),__.inE().count(),__.outE().values("weight").sum())) }], 
+    g_VX1_2X_localXunionXcountXX: [function({g, vid2, vid1}) { return g.V(vid1,vid2).local(__.union(__.count())) }], 
+    g_V_andXhasXage_gt_27X__outE_count_gte_2X_name: [function({g}) { return g.V().and(__.has("age",P.gt(27)),__.outE().count().is(P.gte(2))).values("name") }], 
+    g_V_andXoutE__hasXlabel_personX_and_hasXage_gte_32XX_name: [function({g}) { return g.V().and(__.outE(),__.has(T.label,"person").and().has("age",P.gte(32))).values("name") }], 
+    g_V_asXaX_outXknowsX_and_outXcreatedX_inXcreatedX_asXaX_name: [function({g}) { return g.V().as("a").out("knows").and().out("created").in_("created").as("a").values("name") }], 
+    g_V_asXaX_andXselectXaX_selectXaXX: [function({g}) { return g.V().as("a").and(__.select("a"),__.select("a")) }], 
+    g_V_hasXname_markoX_and_hasXname_markoX_and_hasXname_markoX: [function({g}) { return g.V().has("name","marko").and().has("name","marko").and().has("name","marko") }], 
+    g_V_coinX1X: [function({g}) { return g.V().coin(1.0) }], 
+    g_V_coinX0X: [function({g}) { return g.V().coin(0.0) }], 
+    g_VX1X_outXcreatedX_inXcreatedX_cyclicPath: [function({g, vid1}) { return g.V(vid1).out("created").in_("created").cyclicPath() }], 
+    g_VX1X_outXcreatedX_inXcreatedX_cyclicPath_path: [function({g, vid1}) { return g.V(vid1).out("created").in_("created").cyclicPath().path() }], 
+    g_VX1X_asXaX_outXcreatedX_asXbX_inXcreatedX_asXcX_cyclicPath_fromXaX_toXbX_path: [function({g, vid1}) { return g.V(vid1).as("a").out("created").as("b").in_("created").as("c").cyclicPath().from_("a").to("b").path() }], 
+    g_V_out_in_valuesXnameX_fold_dedupXlocalX_unfold: [function({g}) { return g.V().out().in_().values("name").fold().dedup(Scope.local).unfold() }], 
+    g_V_out_asXxX_in_asXyX_selectXx_yX_byXnameX_fold_dedupXlocal_x_yX_unfold: [function({g}) { return g.V().out().as("x").in_().as("y").select("x","y").by("name").fold().dedup(Scope.local,"x","y").unfold() }], 
+    g_V_both_dedup_name: [function({g}) { return g.V().both().dedup().values("name") }], 
+    g_V_both_hasXlabel_softwareX_dedup_byXlangX_name: [function({g}) { return g.V().both().has(T.label,"software").dedup().by("lang").values("name") }], 
+    g_V_both_name_order_byXa_bX_dedup_value: [function({g, c1}) { return g.V().both().properties("name").order().by(c1).dedup().value() }], 
+    g_V_both_both_name_dedup: [function({g}) { return g.V().both().both().values("name").dedup() }], 
+    g_V_both_both_dedup: [function({g}) { return g.V().both().both().dedup() }], 
+    g_V_both_both_dedup_byXlabelX: [function({g}) { return g.V().both().both().dedup().by(T.label) }], 
+    g_V_group_byXlabelX_byXbothE_weight_dedup_foldX: [function({g}) { return g.V().group().by(T.label).by(__.bothE().values("weight").dedup().fold()) }], 
+    g_V_asXaX_both_asXbX_dedupXa_bX_byXlabelX_selectXa_bX: [function({g}) { return g.V().as("a").both().as("b").dedup("a","b").by(T.label).select("a","b") }], 
+    g_V_asXaX_outXcreatedX_asXbX_inXcreatedX_asXcX_dedupXa_bX_path: [function({g}) { return g.V().as("a").out("created").as("b").in_("created").as("c").dedup("a","b").path() }], 
+    g_V_outE_asXeX_inV_asXvX_selectXeX_order_byXweight_ascX_selectXvX_valuesXnameX_dedup: [function({g}) { return g.V().outE().as("e").inV().as("v").select("e").order().by("weight",Order.asc).select("v").values("name").dedup() }], 
+    g_V_both_both_dedup_byXoutE_countX_name: [function({g}) { return g.V().both().both().dedup().by(__.outE().count()).values("name") }], 
+    g_V_groupCount_selectXvaluesX_unfold_dedup: [function({g}) { return g.V().groupCount().select(Column.values).unfold().dedup() }], 
+    g_V_asXaX_repeatXbothX_timesX3X_emit_name_asXbX_group_byXselectXaXX_byXselectXbX_dedup_order_foldX_selectXvaluesX_unfold_dedup: [function({g}) { return g.V().as("a").repeat(__.both()).times(3).emit().values("name").as("b").group().by(__.select("a")).by(__.select("b").dedup().order().fold()).select(Column.values).unfold().dedup() }], 
+    g_V_repeatXdedupX_timesX2X_count: [function({g}) { return g.V().repeat(__.dedup()).times(2).count() }], 
+    g_V_both_group_by_byXout_dedup_foldX_unfold_selectXvaluesX_unfold_out_order_byXnameX_limitX1X_valuesXnameX: [function({g}) { return g.V().both().group().by().by(__.out().dedup().fold()).unfold().select(Column.values).unfold().out().order().by("name").limit(1).values("name") }], 
+    g_V_bothE_properties_dedup_count: [function({g}) { return g.V().bothE().properties().dedup().count() }], 
+    g_V_both_properties_dedup_count: [function({g}) { return g.V().both().properties().dedup().count() }], 
+    g_V_both_properties_properties_dedup_count: [function({g}) { return g.V().both().properties().properties().dedup().count() }], 
+    g_V_drop: [function({g}) { return g.addV().as("a").addV().as("b").addE("knows").to("a") }, function({g}) { return g.V().drop() }, function({g}) { return g.V() }, function({g}) { return g.E() }], 
+    g_V_outE_drop: [function({g}) { return g.addV().as("a").addV().as("b").addE("knows").to("a") }, function({g}) { return g.V().outE().drop() }, function({g}) { return g.V() }, function({g}) { return g.E() }], 
+    g_V_properties_drop: [function({g}) { return g.addV().property("name","bob").addV().property("name","alice") }, function({g}) { return g.V().properties().drop() }, function({g}) { return g.V() }, function({g}) { return g.V().properties() }], 
+    g_E_propertiesXweightX_drop: [function({g}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","java").as("ripple").addV("person").property(T.id,6).property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property(T.id,7).property("weight",0.5).addE("knows").from_("marko").to("josh").property(T.id,8).property("weight",1.0).addE("created").from_("marko").to("lop").property(T.id,9).property("weight",0.4).addE("created").from_("josh").to("ripple").property(T.id,10).property("weight",1.0).addE("created").from_("josh").to("lop").property(T.id,11).property("weight",0.4).addE("created").from_("peter").to("lop").property(T.id,12).property("weight",0.2) }, function({g}) { return g.E().properties("weight").drop() }, function({g}) { return g.E().properties() }], 
+    g_V_properties_propertiesXstartTimeX_drop: [function({g}) { return g.addV().property("name","bob").property(Cardinality.list,"location","ny","startTime",2014,"endTime",2016).property(Cardinality.list,"location","va","startTime",2016).addV().property("name","alice").property(Cardinality.list,"location","va","startTime",2014,"endTime",2016).property(Cardinality.list,"location","ny","startTime",2016) }, function({g}) { return g.V().properties().properties("startTime").drop() }, function({g}) { return g.V().properties().properties() }, function({g}) { return g.V().properties().properties("startTime") }], 
+    g_V_filterXfalseX: [function({g, pred1}) { return g.V().filter(pred1) }], 
+    g_V_filterXtrueX: [function({g, pred1}) { return g.V().filter(pred1) }], 
+    g_V_filterXlang_eq_javaX: [function({g, pred1}) { return g.V().filter(pred1) }], 
+    g_VX1X_filterXage_gt_30X: [function({g, vid1, pred1}) { return g.V(vid1).filter(pred1) }], 
+    g_VX2X_filterXage_gt_30X: [function({g, vid2, pred1}) { return g.V(vid2).filter(pred1) }], 
+    g_VX1X_out_filterXage_gt_30X: [function({g, vid1, pred1}) { return g.V(vid1).out().filter(pred1) }], 
+    g_V_filterXname_startsWith_m_OR_name_startsWith_pX: [function({g, pred1}) { return g.V().filter(pred1) }], 
+    g_E_filterXfalseX: [function({g, pred1}) { return g.E().filter(pred1) }], 
+    g_E_filterXtrueX: [function({g, pred1}) { return g.E().filter(pred1) }], 
+    g_V_outXcreatedX_hasXname__mapXlengthX_isXgtX3XXX_name: [function({g, l1}) { return g.V().out("created").has("name",__.map(l1).is(P.gt(3))).values("name") }], 
+    g_VX1X_hasXnameX: [function({g, vid1}) { return g.V(vid1).has("name") }], 
+    g_VX1X_hasXcircumferenceX: [function({g, vid1}) { return g.V(vid1).has("circumference") }], 
+    g_VX1X_hasXname_markoX: [function({g, vid1}) { return g.V(vid1).has("name","marko") }], 
+    g_VX2X_hasXname_markoX: [function({g, vid1}) { return g.V(vid1).has("name","marko") }], 
+    g_V_hasXname_markoX: [function({g}) { return g.V().has("name","marko") }], 
+    g_V_hasXname_blahX: [function({g}) { return g.V().has("name","blah") }], 
+    g_V_hasXage_gt_30X: [function({g}) { return g.V().has("age",P.gt(30)) }], 
+    g_V_hasXage_isXgt_30XX: [function({g}) { return g.V().has("age",__.is(P.gt(30))) }], 
+    g_V_hasXlabel_isXsoftwareXX: [function({g}) { return g.V().has(T.label,__.is("software")) }], 
+    g_VX1X_hasXage_gt_30X: [function({g, vid1}) { return g.V(vid1).has("age",P.gt(30)) }], 
+    g_VX4X_hasXage_gt_30X: [function({g, vid4}) { return g.V(vid4).has("age",P.gt(30)) }], 
+    g_VXv1X_hasXage_gt_30X: [function({g, v1}) { return g.V(v1).has("age",P.gt(30)) }], 
+    g_VXv4X_hasXage_gt_30X: [function({g, v4}) { return g.V(v4).has("age",P.gt(30)) }], 
+    g_VX1X_out_hasXid_lt_3X: [function({g, xx1, vid1}) { return g.V(vid1).out().has(T.id,xx1) }], 
+    g_VX1AsStringX_out_hasXid_2AsStringX: [function({g, vid2, vid1}) { return g.V(vid1).out().hasId(vid2) }], 
+    g_VX1X_out_hasXid_2X: [function({g, v2}) { return g.V(v2).has("age",P.gt(30)) }], 
+    g_VX1X_out_hasIdX2X: [function({g, vid2, vid1}) { return g.V(vid1).out().hasId(vid2) }], 
+    g_VX1X_out_hasXid_2_3X: [function({g, vid3, vid2, vid1}) { return g.V(vid1).out().hasId(vid2,vid3) }], 
+    g_VX1X_out_hasXid_2AsString_3AsStringX: [function({g, vid3, vid2, vid1}) { return g.V(vid1).out().hasId(vid2,vid3) }], 
+    g_V_hasXblahX: [function({g}) { return g.V().has("blah") }], 
+    g_EX7X_hasXlabelXknowsX: [function({g, eid7}) { return g.E(eid7).hasLabel("knows") }], 
+    g_E_hasXlabelXknowsX: [function({g}) { return g.E().hasLabel("knows") }], 
+    g_E_hasLabelXuses_traversesX: [function({g}) { return g.E().hasLabel("uses","traverses") }], 
+    g_V_hasLabelXperson_software_blahX: [function({g}) { return g.V().hasLabel("person","software","blah") }], 
+    g_V_hasXperson_name_markoX_age: [function({g}) { return g.V().has("person","name","marko").values("age") }], 
+    g_VX1X_outE_hasXweight_inside_0_06X_inV: [function({g, vid1}) { return g.V(vid1).outE().has("weight",P.gt(0.0).and(P.lt(0.6))).inV() }], 
+    g_EX11X_outV_outE_hasXid_10X: [function({g, eid11, eid10}) { return g.E(eid11).outV().outE().has(T.id,eid10) }], 
+    g_EX11X_outV_outE_hasXid_10AsStringX: [function({g, eid11, eid10}) { return g.E(eid11).outV().outE().has(T.id,eid10) }], 
+    g_V_hasXlocationX: [function({g}) { return g.V().has("location") }], 
+    g_V_hasLabelXpersonX_hasXage_notXlteX10X_andXnotXbetweenX11_20XXXX_andXltX29X_orXeqX35XXXX_name: [function({g}) { return g.V().hasLabel("person").has("age",P.gt(10).or(P.gte(11).and(P.lt(20))).and(P.lt(29).or(P.eq(35)))).values("name") }], 
+    g_V_in_hasIdXneqX1XX: [function({g, xx1}) { return g.V().in_().hasId(xx1) }], 
+    g_V_hasXage_withinX27X_count: [function({g}) { return g.V().has("age",P.within([27])).count() }], 
+    g_V_hasXage_withinX27_29X_count: [function({g}) { return g.V().has("age",P.within([27, 29])).count() }], 
+    g_V_hasXage_withoutX27X_count: [function({g}) { return g.V().has("age",P.without([27])).count() }], 
+    g_V_hasXage_withoutX27_29X_count: [function({g}) { return g.V().has("age",P.without([27, 29])).count() }], 
+    g_V_both_dedup_properties_hasKeyXageX_value: [function({g}) { return g.V().both().properties().dedup().hasKey("age").value() }], 
+    g_V_both_dedup_properties_hasKeyXageX_hasValueXgtX30XX_value: [function({g}) { return g.V().both().properties().dedup().hasKey("age").hasValue(P.gt(30)).value() }], 
+    g_V_bothE_properties_dedup_hasKeyXweightX_value: [function({g}) { return g.V().bothE().properties().dedup().hasKey("weight").value() }], 
+    g_V_bothE_properties_dedup_hasKeyXweightX_hasValueXltX0d3XX_value: [function({g}) { return g.V().bothE().properties().dedup().hasKey("weight").hasValue(P.lt(0.3)).value() }], 
+    g_V_hasNotXageX_name: [function({g}) { return g.V().hasNot("age").values("name") }], 
+    g_V_hasIdX1X_hasIdX2X: [function({g, vid2, vid1}) { return g.V().hasId(vid1).hasId(vid2) }], 
+    g_V_hasLabelXpersonX_hasLabelXsoftwareX: [function({g}) { return g.V().hasLabel("person").hasLabel("software") }], 
+    g_V_hasIdXemptyX_count: [function({g, xx1}) { return g.V().hasId(xx1).count() }], 
+    g_V_hasIdXwithinXemptyXX_count: [function({g, xx1}) { return g.V().hasId(xx1).count() }], 
+    g_V_hasIdXwithoutXemptyXX_count: [function({g, xx1}) { return g.V().hasId(xx1).count() }], 
+    g_V_notXhasIdXwithinXemptyXXX_count: [function({g, xx1}) { return g.V().not(__.hasId(xx1)).count() }], 
+    g_V_hasXname_containingXarkXX: [function({g}) { return g.V().has("name",TextP.containing("ark")) }], 
+    g_V_hasXname_startingWithXmarXX: [function({g}) { return g.V().has("name",TextP.startingWith("mar")) }], 
+    g_V_hasXname_endingWithXasXX: [function({g}) { return g.V().has("name",TextP.endingWith("as")) }], 
+    g_V_hasXperson_name_containingXoX_andXltXmXXX: [function({g}) { return g.V().has("person","name",TextP.containing("o").and(P.lt("m"))) }], 
+    g_V_hasXname_gtXmX_andXcontainingXoXXX: [function({g}) { return g.V().has("name",P.gt("m").and(TextP.containing("o"))) }], 
+    g_V_hasXname_not_containingXarkXX: [function({g}) { return g.V().has("name",TextP.notContaining("ark")) }], 
+    g_V_hasXname_not_startingWithXmarXX: [function({g}) { return g.V().has("name",TextP.notStartingWith("mar")) }], 
+    g_V_hasXname_not_endingWithXasXX: [function({g}) { return g.V().has("name",TextP.notEndingWith("as")) }], 
+    g_V_hasXp_neqXvXX: [function({g}) { return g.V().has("p",P.neq("v")) }], 
+    g_V_hasXage_gtX18X_andXltX30XXorXgtx35XXX: [function({g}) { return g.V().has("age",P.gt(18).and(P.lt(30)).or(P.gt(35))) }], 
+    g_V_hasXage_gtX18X_andXltX30XXorXltx35XXX: [function({g}) { return g.V().has("age",P.gt(18).and(P.lt(30)).and(P.lt(35))) }], 
+    g_V_valuesXageX_isX32X: [function({g}) { return g.V().values("age").is(32) }], 
+    g_V_valuesXageX_isXlte_30X: [function({g}) { return g.V().values("age").is(P.lte(30)) }], 
+    g_V_valuesXageX_isXgte_29X_isXlt_34X: [function({g}) { return g.V().values("age").is(P.gte(29)).is(P.lt(34)) }], 
+    g_V_whereXinXcreatedX_count_isX1XX_valuesXnameX: [function({g}) { return g.V().where(__.in_("created").count().is(1)).values("name") }], 
+    g_V_whereXinXcreatedX_count_isXgte_2XX_valuesXnameX: [function({g}) { return g.V().where(__.in_("created").count().is(P.gte(2))).values("name") }], 
+    g_V_orXhasXage_gt_27X__outE_count_gte_2X_name: [function({g}) { return g.V().or(__.has("age",P.gt(27)),__.outE().count().is(P.gte(2))).values("name") }], 
+    g_V_orXoutEXknowsX__hasXlabel_softwareX_or_hasXage_gte_35XX_name: [function({g}) { return g.V().or(__.outE("knows"),__.has(T.label,"software").or().has("age",P.gte(35))).values("name") }], 
+    g_V_asXaX_orXselectXaX_selectXaXX: [function({g}) { return g.V().as("a").or(__.select("a"),__.select("a")) }], 
+    g_VX1X_out_limitX2X: [function({g, vid1}) { return g.V(vid1).out().limit(2) }], 
+    g_V_localXoutE_limitX1X_inVX_limitX3X: [function({g}) { return g.V().local(__.outE().limit(1)).inV().limit(3) }], 
+    g_VX1X_outXknowsX_outEXcreatedX_rangeX0_1X_inV: [function({g, vid1}) { return g.V(vid1).out("knows").outE("created").range(0,1).inV() }], 
+    g_VX1X_outXknowsX_outXcreatedX_rangeX0_1X: [function({g, vid1}) { return g.V(vid1).out("knows").out("created").range(0,1) }], 
+    g_VX1X_outXcreatedX_inXcreatedX_rangeX1_3X: [function({g, vid1}) { return g.V(vid1).out("created").in_("created").range(1,3) }], 
+    g_VX1X_outXcreatedX_inEXcreatedX_rangeX1_3X_outV: [function({g, vid1}) { return g.V(vid1).out("created").inE("created").range(1,3).outV() }], 
+    g_V_repeatXbothX_timesX3X_rangeX5_11X: [function({g}) { return g.V().repeat(__.both()).times(3).range(5,11) }], 
+    g_V_asXaX_in_asXbX_in_asXcX_selectXa_b_cX_byXnameX_limitXlocal_2X: [function({g}) { return g.V().as("a").in_().as("b").in_().as("c").select("a","b","c").by("name").limit(Scope.local,2) }], 
+    g_V_asXaX_in_asXbX_in_asXcX_selectXa_b_cX_byXnameX_limitXlocal_1X: [function({g}) { return g.V().as("a").in_().as("b").in_().as("c").select("a","b","c").by("name").limit(Scope.local,1) }], 
+    g_V_asXaX_out_asXbX_out_asXcX_selectXa_b_cX_byXnameX_rangeXlocal_1_3X: [function({g}) { return g.V().as("a").out().as("b").out().as("c").select("a","b","c").by("name").range(Scope.local,1,3) }], 
+    g_V_asXaX_out_asXbX_out_asXcX_selectXa_b_cX_byXnameX_rangeXlocal_1_2X: [function({g}) { return g.V().as("a").out().as("b").out().as("c").select("a","b","c").by("name").range(Scope.local,1,2) }], 
+    g_V_asXaX_out_asXaX_out_asXaX_selectXmixed_aX_byXunfold_valuesXnameX_foldX_rangeXlocal_1_3X: [function({g}) { return g.V().as("a").out().as("a").out().as("a").select(Pop.mixed,"a").by(__.unfold().values("name").fold()).range(Scope.local,1,3) }], 
+    g_V_asXaX_out_asXaX_out_asXaX_selectXmixed_aX_byXunfold_valuesXnameX_foldX_rangeXlocal_1_2X: [function({g}) { return g.V().as("a").out().as("a").out().as("a").select(Pop.mixed,"a").by(__.unfold().values("name").fold()).range(Scope.local,1,2) }], 
+    g_V_hasLabelXpersonX_order_byXageX_skipX1X_valuesXnameX: [function({g}) { return g.V().hasLabel("person").order().by("age").skip(1).values("name") }], 
+    g_V_asXaX_out_asXaX_out_asXaX_selectXmixed_aX_byXunfold_valuesXnameX_foldX_rangeXlocal_4_5X: [function({g}) { return g.V().as("a").out().as("a").out().as("a").select(Pop.mixed,"a").by(__.unfold().values("name").fold()).range(Scope.local,4,5) }], 
+    g_V_outE_valuesXweightX_fold_orderXlocalX_skipXlocal_2X: [function({g}) { return g.V().outE().values("weight").fold().order(Scope.local).skip(Scope.local,2) }], 
+    g_V_asXaX_in_asXaX_in_asXaX_selectXmixed_aX_byXunfold_valuesXnameX_foldX_limitXlocal_1X: [function({g}) { return g.V().as("a").in_().as("a").in_().as("a").select(Pop.mixed,"a").by(__.unfold().values("name").fold()).limit(Scope.local,1) }], 
+    g_V_asXaX_in_asXaX_in_asXaX_selectXmixed_aX_byXunfold_valuesXnameX_foldX_limitXlocal_2X: [function({g}) { return g.V().as("a").in_().as("a").in_().as("a").select(Pop.mixed,"a").by(__.unfold().values("name").fold()).limit(Scope.local,2) }], 
+    g_V_hasLabelXpersonX_order_byXageX_valuesXnameX_skipX1X: [function({g}) { return g.V().hasLabel("person").order().by("age").values("name").skip(1) }], 
+    g_E_sampleX1X: [function({g}) { return g.E().sample(1) }], 
+    g_E_sampleX2X_byXweightX: [function({g}) { return g.E().sample(2).by("weight") }], 
+    g_V_localXoutE_sampleX1X_byXweightXX: [function({g}) { return g.V().local(__.outE().sample(1).by("weight")) }], 
+    g_V_group_byXlabelX_byXbothE_weight_sampleX2X_foldX: [function({g}) { return g.V().group().by(T.label).by(__.bothE().values("weight").sample(2).fold()) }], 
+    g_V_group_byXlabelX_byXbothE_weight_fold_sampleXlocal_5XX: [function({g}) { return g.V().group().by(T.label).by(__.bothE().values("weight").fold().sample(Scope.local,5)) }], 
+    g_VX1X_outXcreatedX_inXcreatedX_simplePath: [function({g, vid1}) { return g.V(vid1).out("created").in_("created").simplePath() }], 
+    g_V_repeatXboth_simplePathX_timesX3X_path: [function({g}) { return g.V().repeat(__.both().simplePath()).times(3).path() }], 
+    g_V_asXaX_out_asXbX_out_asXcX_simplePath_byXlabelX_fromXbX_toXcX_path_byXnameX: [function({g}) { return g.V().as("a").out().as("b").out().as("c").simplePath().by(T.label).from_("b").to("c").path().by("name") }], 
+    g_V_valuesXnameX_order_tailXglobal_2X: [function({g}) { return g.V().values("name").order().tail(Scope.global,2) }], 
+    g_V_valuesXnameX_order_tailX2X: [function({g}) { return g.V().values("name").order().tail(2) }], 
+    g_V_valuesXnameX_order_tail: [function({g}) { return g.V().values("name").order().tail() }], 
+    g_V_valuesXnameX_order_tailX7X: [function({g}) { return g.V().values("name").order().tail(7) }], 
+    g_V_repeatXbothX_timesX3X_tailX7X: [function({g}) { return g.V().repeat(__.both()).times(3).tail(7) }], 
+    g_V_repeatXin_outX_timesX3X_tailX7X_count: [function({g}) { return g.V().repeat(__.in_().out()).times(3).tail(7).count() }], 
+    g_V_asXaX_out_asXaX_out_asXaX_selectXaX_byXunfold_valuesXnameX_foldX_tailXlocal_1X: [function({g}) { return g.V().as("a").out().as("a").out().as("a").select("a").by(__.unfold().values("name").fold()).tail(Scope.local,1) }], 
+    g_V_asXaX_out_asXaX_out_asXaX_selectXaX_byXunfold_valuesXnameX_foldX_tailXlocalX: [function({g}) { return g.V().as("a").out().as("a").out().as("a").select("a").by(__.unfold().values("name").fold()).tail(Scope.local) }], 
+    g_V_asXaX_out_asXbX_out_asXcX_selectXa_b_cX_byXnameX_tailXlocal_2X: [function({g}) { return g.V().as("a").out().as("b").out().as("c").select("a","b","c").by("name").tail(Scope.local,2) }], 
+    g_V_asXaX_out_asXbX_out_asXcX_selectXa_b_cX_byXnameX_tailXlocal_1X: [function({g}) { return g.V().as("a").out().as("b").out().as("c").select("a","b","c").by("name").tail(Scope.local,1) }], 
+    g_V_asXaX_out_asXaX_out_asXaX_selectXmixed_aX_byXunfold_valuesXnameX_foldX_tailXlocal_1X: [function({g}) { return g.V().as("a").out().as("a").out().as("a").select(Pop.mixed,"a").by(__.unfold().values("name").fold()).tail(Scope.local,1) }], 
+    g_V_asXaX_out_asXaX_out_asXaX_selectXmixed_aX_byXunfold_valuesXnameX_foldX_tailXlocalX: [function({g}) { return g.V().as("a").out().as("a").out().as("a").select(Pop.mixed,"a").by(__.unfold().values("name").fold()).tail(Scope.local) }], 
+    g_V_asXaX_out_asXaX_out_asXaX_selectXmixed_aX_byXlimitXlocal_0XX_tailXlocal_1X: [function({g}) { return g.V().as("a").out().as("a").out().as("a").select(Pop.mixed,"a").by(__.limit(Scope.local,0)).tail(Scope.local,1) }], 
+    g_V_asXaX_out_asXaX_out_asXaX_selectXmixed_aX_byXunfold_valuesXnameX_foldX_tailXlocal_2X: [function({g}) { return g.V().as("a").out().as("a").out().as("a").select(Pop.mixed,"a").by(__.unfold().values("name").fold()).tail(Scope.local,2) }], 
+    g_V_hasXageX_asXaX_out_in_hasXageX_asXbX_selectXa_bX_whereXa_eqXbXX: [function({g}) { return g.V().has("age").as("a").out().in_().has("age").as("b").select("a","b").where("a",P.eq("b")) }], 
+    g_V_hasXageX_asXaX_out_in_hasXageX_asXbX_selectXa_bX_whereXa_neqXbXX: [function({g}) { return g.V().has("age").as("a").out().in_().has("age").as("b").select("a","b").where("a",P.neq("b")) }], 
+    g_V_hasXageX_asXaX_out_in_hasXageX_asXbX_selectXa_bX_whereXb_hasXname_markoXX: [function({g}) { return g.V().has("age").as("a").out().in_().has("age").as("b").select("a","b").where(__.as("b").has("name","marko")) }], 
+    g_V_hasXageX_asXaX_out_in_hasXageX_asXbX_selectXa_bX_whereXa_outXknowsX_bX: [function({g}) { return g.V().has("age").as("a").out().in_().has("age").as("b").select("a","b").where(__.as("a").out("knows").as("b")) }], 
+    g_V_asXaX_outXcreatedX_whereXasXaX_name_isXjoshXX_inXcreatedX_name: [function({g}) { return g.V().as("a").out("created").where(__.as("a").values("name").is("josh")).in_("created").values("name") }], 
+    g_withSideEffectXa_josh_peterX_VX1X_outXcreatedX_inXcreatedX_name_whereXwithinXaXX: [function({g, xx1, vid1}) { return g.withSideEffect("a",xx1).V(vid1).out("created").in_("created").values("name").where(P.within(["a"])) }], 
+    g_VX1X_asXaX_outXcreatedX_inXcreatedX_asXbX_whereXa_neqXbXX_name: [function({g, vid1}) { return g.V(vid1).as("a").out("created").in_("created").as("b").where("a",P.neq("b")).values("name") }], 
+    g_VX1X_asXaX_outXcreatedX_inXcreatedX_asXbX_whereXasXbX_outXcreatedX_hasXname_rippleXX_valuesXage_nameX: [function({g, vid1}) { return g.V(vid1).as("a").out("created").in_("created").as("b").where(__.as("b").out("created").has("name","ripple")).values("age","name") }], 
+    g_VX1X_asXaX_outXcreatedX_inXcreatedX_whereXeqXaXX_name: [function({g, vid1}) { return g.V(vid1).as("a").out("created").in_("created").where(P.eq("a")).values("name") }], 
+    g_VX1X_asXaX_outXcreatedX_inXcreatedX_whereXneqXaXX_name: [function({g, vid1}) { return g.V(vid1).as("a").out("created").in_("created").where(P.neq("a")).values("name") }], 
+    g_VX1X_out_aggregateXxX_out_whereXnotXwithinXaXXX: [function({g, vid1}) { return g.V(vid1).out().aggregate("x").out().where(P.without(["x"])) }], 
+    g_withSideEffectXa_g_VX2XX_VX1X_out_whereXneqXaXX: [function({g, vid1, v2}) { return g.withSideEffect("a",v2).V(vid1).out().where(P.neq("a")) }], 
+    g_VX1X_repeatXbothEXcreatedX_whereXwithoutXeXX_aggregateXeX_otherVX_emit_path: [function({g, vid1}) { return g.V(vid1).repeat(__.bothE("created").where(P.without(["e"])).aggregate("e").otherV()).emit().path() }], 
+    g_V_whereXnotXoutXcreatedXXX_name: [function({g}) { return g.V().where(__.not(__.out("created"))).values("name") }], 
+    g_V_asXaX_out_asXbX_whereXandXasXaX_outXknowsX_asXbX__orXasXbX_outXcreatedX_hasXname_rippleX__asXbX_inXknowsX_count_isXnotXeqX0XXXXX_selectXa_bX: [function({g}) { return g.V().as("a").out().as("b").where(__.and(__.as("a").out("knows").as("b"),__.or(__.as("b").out("created").has("name","ripple"),__.as("b").in_("knows").count().is(P.neq(0))))).select("a","b") }], 
+    g_V_whereXoutXcreatedX_and_outXknowsX_or_inXknowsXX_valuesXnameX: [function({g}) { return g.V().where(__.out("created").and().out("knows").or().in_("knows")).values("name") }], 
+    g_V_asXaX_outXcreatedX_asXbX_whereXandXasXbX_in__notXasXaX_outXcreatedX_hasXname_rippleXXX_selectXa_bX: [function({g}) { return g.V().as("a").out("created").as("b").where(__.and(__.as("b").in_(),__.not(__.as("a").out("created").has("name","ripple")))).select("a","b") }], 
+    g_V_asXaX_outXcreatedX_asXbX_inXcreatedX_asXcX_bothXknowsX_bothXknowsX_asXdX_whereXc__notXeqXaX_orXeqXdXXXX_selectXa_b_c_dX: [function({g}) { return g.V().as("a").out("created").as("b").in_("created").as("c").both("knows").both("knows").as("d").where("c",P.neq("a").and(P.neq("d"))).select("a","b","c","d") }], 
+    g_V_asXaX_out_asXbX_whereXin_count_isXeqX3XX_or_whereXoutXcreatedX_and_hasXlabel_personXXX_selectXa_bX: [function({g}) { return g.V().as("a").out().as("b").where(__.as("b").in_().count().is(P.eq(3)).or().where(__.as("b").out("created").and().as("b").has(T.label,"person"))).select("a","b") }], 
+    g_V_asXaX_outXcreatedX_inXcreatedX_asXbX_whereXa_gtXbXX_byXageX_selectXa_bX_byXnameX: [function({g}) { return g.V().as("a").out("created").in_("created").as("b").where("a",P.gt("b")).by("age").select("a","b").by("name") }], 
+    g_V_asXaX_outEXcreatedX_asXbX_inV_asXcX_whereXa_gtXbX_orXeqXbXXX_byXageX_byXweightX_byXweightX_selectXa_cX_byXnameX: [function({g}) { return g.V().as("a").outE("created").as("b").inV().as("c").where("a",P.gt("b").or(P.eq("b"))).by("age").by("weight").by("weight").select("a","c").by("name") }], 
+    g_V_asXaX_outEXcreatedX_asXbX_inV_asXcX_inXcreatedX_asXdX_whereXa_ltXbX_orXgtXcXX_andXneqXdXXX_byXageX_byXweightX_byXinXcreatedX_valuesXageX_minX_selectXa_c_dX: [function({g}) { return g.V().as("a").outE("created").as("b").inV().as("c").in_("created").as("d").where("a",P.lt("b").or(P.gt("c")).and(P.neq("d"))).by("age").by("weight").by(__.in_("created").values("age").min()).select("a","c","d").by("name") }], 
+    g_VX1X_asXaX_out_hasXageX_whereXgtXaXX_byXageX_name: [function({g, vid1}) { return g.V(vid1).as("a").out().has("age").where(P.gt("a")).by("age").values("name") }], 
+    g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX: [function({g, vid1}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","java").as("ripple").addV("person").property(T.id,6).property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property(T.id,7).property("weight",0.5).addE("knows").from_("marko").to("josh").property(T.id,8).property("weight",1.0).addE("created").from_("marko").to("lop").property(T.id,9).property("weight",0.4).addE("created").from_("josh").to("ripple").property(T.id,10).property("weight",1.0).addE("created").from_("josh").to("lop").property(T.id,11).property("weight",0.4).addE("created").from_("peter").to("lop").property(T.id,12).property("weight",0.2) }, function({g, vid1}) { return g.V(vid1).as("a").out("created").addE("createdBy").to("a") }, function({g, vid1}) { return g.E() }, function({g, vid1}) { return g.V(vid1).inE() }], 
+    g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX_propertyXweight_2X: [function({g, vid1}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","java").as("ripple").addV("person").property(T.id,6).property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property(T.id,7).property("weight",0.5).addE("knows").from_("marko").to("josh").property(T.id,8).property("weight",1.0).addE("created").from_("marko").to("lop").property(T.id,9).property("weight",0.4).addE("created").from_("josh").to("ripple").property(T.id,10).property("weight",1.0).addE("created").from_("josh").to("lop").property(T.id,11).property("weight",0.4).addE("created").from_("peter").to("lop").property(T.id,12).property("weight",0.2) }, function({g, vid1}) { return g.V(vid1).as("a").out("created").addE("createdBy").to("a").property("weight",2.0) }, function({g, vid1}) { return g.E() }, function({g, vid1}) { return g.V(vid1).bothE() }, function({g, vid1}) { return g.V(vid1).inE().has("weight",2.0) }], 
+    g_V_outE_propertyXweight_nullX: [function({g}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","java").as("ripple").addV("person").property(T.id,6).property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property(T.id,7).property("weight",0.5).addE("knows").from_("marko").to("josh").property(T.id,8).property("weight",1.0).addE("created").from_("marko").to("lop").property(T.id,9).property("weight",0.4).addE("created").from_("josh").to("ripple").property(T.id,10).property("weight",1.0).addE("created").from_("josh").to("lop").property(T.id,11).property("weight",0.4).addE("created").from_("peter").to("lop").property(T.id,12).property("weight",0.2) }, function({g}) { return g.V().outE().property("weight",null) }, function({g}) { return g.E().properties("weight") }], 
+    g_V_aggregateXxX_asXaX_selectXxX_unfold_addEXexistsWithX_toXaX_propertyXtime_nowX: [function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","java").as("ripple").addV("person").property(T.id,6).property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property(T.id,7).property("weight",0.5).addE("knows").from_("marko").to("josh").property(T.id,8).property("weight",1.0).addE("created").from_("marko").to("lop").property(T.id,9).property("weight",0.4).addE("created").from_("josh").to("ripple").property(T.id,10).property("weight",1.0).addE("created").from_("josh").to("lop").property(T.id,11).property("weight",0.4).addE("created").from_("peter").to("lop").property(T.id,12).property("weight",0.2) }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V().aggregate("x").as("a").select("x").unfold().addE("existsWith").to("a").property("time","now") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.E() }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid1).bothE() }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid1).inE("existsWith") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid1).outE("existsWith") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid1).bothE("existsWith").has("time","now") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid2).bothE() }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid2).inE("existsWith") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid2).outE("existsWith") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid2).bothE("existsWith").has("time","now") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid3).bothE() }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid3).inE("existsWith") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid3).outE("existsWith") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid3).bothE("existsWith").has("time","now") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid4).bothE() }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid4).inE("existsWith") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid4).outE("existsWith") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid4).bothE("existsWith").has("time","now") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid5).bothE() }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid5).inE("existsWith") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid5).outE("existsWith") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid5).bothE("existsWith").has("time","now") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid6).bothE() }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid6).inE("existsWith") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid6).outE("existsWith") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid6).bothE("existsWith").has("time","now") }], 
+    g_V_asXaX_outXcreatedX_inXcreatedX_whereXneqXaXX_asXbX_addEXcodeveloperX_fromXaX_toXbX_propertyXyear_2009X: [function({g, vid1, vid2, vid4, vid6}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","java").as("ripple").addV("person").property(T.id,6).property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property(T.id,7).property("weight",0.5).addE("knows").from_("marko").to("josh").property(T.id,8).property("weight",1.0).addE("created").from_("marko").to("lop").property(T.id,9).property("weight",0.4).addE("created").from_("josh").to("ripple").property(T.id,10).property("weight",1.0).addE("created").from_("josh").to("lop").property(T.id,11).property("weight",0.4).addE("created").from_("peter").to("lop").property(T.id,12).property("weight",0.2) }, function({g, vid1, vid2, vid4, vid6}) { return g.V().as("a").out("created").in_("created").where(P.neq("a")).as("b").addE("codeveloper").from_("a").to("b").property("year",2009) }, function({g, vid1, vid2, vid4, vid6}) { return g.E() }, function({g, vid1, vid2, vid4, vid6}) { return g.V(vid1).bothE() }, function({g, vid1, vid2, vid4, vid6}) { return g.V(vid1).inE("codeveloper") }, function({g, vid1, vid2, vid4, vid6}) { return g.V(vid1).outE("codeveloper") }, function({g, vid1, vid2, vid4, vid6}) { return g.V(vid1).bothE("codeveloper").has("year",2009) }, function({g, vid1, vid2, vid4, vid6}) { return g.V(vid2).bothE() }, function({g, vid1, vid2, vid4, vid6}) { return g.V(vid4).bothE() }, function({g, vid1, vid2, vid4, vid6}) { return g.V(vid4).inE("codeveloper") }, function({g, vid1, vid2, vid4, vid6}) { return g.V(vid4).outE("codeveloper") }, function({g, vid1, vid2, vid4, vid6}) { return g.V(vid4).bothE("codeveloper").has("year",2009) }, function({g, vid1, vid2, vid4, vid6}) { return g.V(vid6).bothE() }, function({g, vid1, vid2, vid4, vid6}) { return g.V(vid6).inE("codeveloper") }, function({g, vid1, vid2, vid4, vid6}) { return g.V(vid6).outE("codeveloper") }, function({g, vid1, vid2, vid4, vid6}) { return g.V(vid6).bothE("codeveloper").has("year",2009) }], 
+    g_V_asXaX_inXcreatedX_addEXcreatedByX_fromXaX_propertyXyear_2009X_propertyXacl_publicX: [function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","java").as("ripple").addV("person").property(T.id,6).property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property(T.id,7).property("weight",0.5).addE("knows").from_("marko").to("josh").property(T.id,8).property("weight",1.0).addE("created").from_("marko").to("lop").property(T.id,9).property("weight",0.4).addE("created").from_("josh").to("ripple").property(T.id,10).property("weight",1.0).addE("created").from_("josh").to("lop").property(T.id,11).property("weight",0.4).addE("created").from_("peter").to("lop").property(T.id,12).property("weight",0.2) }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V().as("a").in_("created").addE("createdBy").from_("a").property("year",2009).property("acl","public") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.E() }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid1).bothE() }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid1).inE("createdBy") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid1).outE("createdBy") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid1).bothE("createdBy").has("year",2009).has("acl","public") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid2).bothE() }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid3).bothE() }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid3).inE("createdBy") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid3).outE("createdBy") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid3).bothE("createdBy").has("year",2009).has("acl","public") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid4).bothE() }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid4).inE("createdBy") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid4).outE("createdBy") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid4).bothE("createdBy").has("year",2009).has("acl","public") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid5).bothE() }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid5).inE("createdBy") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid5).outE("createdBy") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid5).bothE("createdBy").has("year",2009).has("acl","public") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid6).bothE() }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid6).inE("createdBy") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid6).outE("createdBy") }, function({g, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid6).bothE("createdBy").has("year",2009).has("acl","public") }], 
+    g_withSideEffectXb_bX_VXaX_addEXknowsX_toXbX_propertyXweight_0_5X: [function({g, v6, v1}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","java").as("ripple").addV("person").property(T.id,6).property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property(T.id,7).property("weight",0.5).addE("knows").from_("marko").to("josh").property(T.id,8).property("weight",1.0).addE("created").from_("marko").to("lop").property(T.id,9).property("weight",0.4).addE("created").from_("josh").to("ripple").property(T.id,10).property("weight",1.0).addE("created").from_("josh").to("lop").property(T.id,11).property("weight",0.4).addE("created").from_("peter").to("lop").property(T.id,12).property("weight",0.2) }, function({g, v6, v1}) { return g.withSideEffect("b",v6).V(v1).addE("knows").to("b").property("weight",0.5) }, function({g, v6, v1}) { return g.E() }, function({g, v6, v1}) { return g.V(v1).bothE() }, function({g, v6, v1}) { return g.V(v1).inE("knows") }, function({g, v6, v1}) { return g.V(v1).outE("knows") }, function({g, v6, v1}) { return g.V(v1).bothE("knows").has("weight",0.5) }, function({g, v6, v1}) { return g.V(v6).bothE() }, function({g, v6, v1}) { return g.V(v6).inE("knows") }, function({g, v6, v1}) { return g.V(v6).outE("knows") }, function({g, v6, v1}) { return g.V(v6).bothE("knows").has("weight",0.5) }], 
+    g_addV_asXfirstX_repeatXaddEXnextX_toXaddVX_inVX_timesX5X_addEXnextX_toXselectXfirstXX: [function({g}) { return g.addV().as("first").repeat(__.addE("next").to(__.addV()).inV()).times(5).addE("next").to(__.select("first")) }, function({g}) { return g.V() }, function({g}) { return g.E() }, function({g}) { return g.E().hasLabel("next") }, function({g}) { return g.V().limit(1).bothE() }, function({g}) { return g.V().limit(1).inE() }, function({g}) { return g.V().limit(1).outE() }], 
+    g_V_hasXname_markoX_asXaX_outEXcreatedX_asXbX_inV_addEXselectXbX_labelX_toXaX: [function({g, v1}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","java").as("ripple").addV("person").property(T.id,6).property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property(T.id,7).property("weight",0.5).addE("knows").from_("marko").to("josh").property(T.id,8).property("weight",1.0).addE("created").from_("marko").to("lop").property(T.id,9).property("weight",0.4).addE("created").from_("josh").to("ripple").property(T.id,10).property("weight",1.0).addE("created").from_("josh").to("lop").property(T.id,11).property("weight",0.4).addE("created").from_("peter").to("lop").property(T.id,12).property("weight",0.2) }, function({g, v1}) { return g.V().has("name","marko").as("a").outE("created").as("b").inV().addE(__.select("b").label()).to("a") }, function({g, v1}) { return g.E() }, function({g, v1}) { return g.V(v1).bothE() }, function({g, v1}) { return g.V(v1).inE("created") }, function({g, v1}) { return g.V(v1).in_("created").has("name","lop") }, function({g, v1}) { return g.V(v1).outE("created") }], 
+    g_addEXV_outE_label_groupCount_orderXlocalX_byXvalues_descX_selectXkeysX_unfold_limitX1XX_fromXV_hasXname_vadasXX_toXV_hasXname_lopXX: [function({g, v2}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","java").as("ripple").addV("person").property(T.id,6).property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property(T.id,7).property("weight",0.5).addE("knows").from_("marko").to("josh").property(T.id,8).property("weight",1.0).addE("created").from_("marko").to("lop").property(T.id,9).property("weight",0.4).addE("created").from_("josh").to("ripple").property(T.id,10).property("weight",1.0).addE("created").from_("josh").to("lop").property(T.id,11).property("weight",0.4).addE("created").from_("peter").to("lop").property(T.id,12).property("weight",0.2) }, function({g, v2}) { return g.addE(__.V().outE().label().groupCount().order(Scope.local).by(Column.values,Order.desc).select(Column.keys).unfold().limit(1)).from_(__.V().has("name","vadas")).to(__.V().has("name","lop")) }, function({g, v2}) { return g.E() }, function({g, v2}) { return g.V(v2).bothE() }, function({g, v2}) { return g.V(v2).inE("knows") }, function({g, v2}) { return g.V(v2).outE("created") }, function({g, v2}) { return g.V(v2).out("created").has("name","lop") }], 
+    g_addEXknowsX_fromXaX_toXbX_propertyXweight_0_1X: [function({g, v6, xx1, v1}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","java").as("ripple").addV("person").property(T.id,6).property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property(T.id,7).property("weight",0.5).addE("knows").from_("marko").to("josh").property(T.id,8).property("weight",1.0).addE("created").from_("marko").to("lop").property(T.id,9).property("weight",0.4).addE("created").from_("josh").to("ripple").property(T.id,10).property("weight",1.0).addE("created").from_("josh").to("lop").property(T.id,11).property("weight",0.4).addE("created").from_("peter").to("lop").property(T.id,12).property("weight",0.2) }, function({g, v6, xx1, v1}) { return g.addE("knows").from_(v1).to(v6).property("weight",xx1) }, function({g, v6, xx1, v1}) { return g.E() }, function({g, v6, xx1, v1}) { return g.V(v1).outE("knows") }, function({g, v6, xx1, v1}) { return g.V(v1).out("knows").has("name","peter") }], 
+    g_VXaX_addEXknowsX_toXbX_propertyXweight_0_1X: [function({g, v6, xx1, v1}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","java").as("ripple").addV("person").property(T.id,6).property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property(T.id,7).property("weight",0.5).addE("knows").from_("marko").to("josh").property(T.id,8).property("weight",1.0).addE("created").from_("marko").to("lop").property(T.id,9).property("weight",0.4).addE("created").from_("josh").to("ripple").property(T.id,10).property("weight",1.0).addE("created").from_("josh").to("lop").property(T.id,11).property("weight",0.4).addE("created").from_("peter").to("lop").property(T.id,12).property("weight",0.2) }, function({g, v6, xx1, v1}) { return g.V(v1).addE("knows").to(v6).property("weight",xx1) }, function({g, v6, xx1, v1}) { return g.E() }, function({g, v6, xx1, v1}) { return g.V(v1).outE("knows") }, function({g, v6, xx1, v1}) { return g.V(v1).out("knows").has("name","peter") }], 
+    g_VX1X_addVXanimalX_propertyXage_selectXaX_byXageXX_propertyXname_puppyX: [function({g, vid1}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","java").as("ripple").addV("person").property(T.id,6).property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property(T.id,7).property("weight",0.5).addE("knows").from_("marko").to("josh").property(T.id,8).property("weight",1.0).addE("created").from_("marko").to("lop").property(T.id,9).property("weight",0.4).addE("created").from_("josh").to("ripple").property(T.id,10).property("weight",1.0).addE("created").from_("josh").to("lop").property(T.id,11).property("weight",0.4).addE("created").from_("peter").to("lop").property(T.id,12).property("weight",0.2) }, function({g, vid1}) { return g.V(vid1).as("a").addV("animal").property("age",__.select("a").by("age")).property("name","puppy") }, function({g, vid1}) { return g.V().has("animal","age",29) }], 
+    g_V_addVXanimalX_propertyXage_0X: [function({g}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","java").as("ripple").addV("person").property(T.id,6).property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property(T.id,7).property("weight",0.5).addE("knows").from_("marko").to("josh").property(T.id,8).property("weight",1.0).addE("created").from_("marko").to("lop").property(T.id,9).property("weight",0.4).addE("created").from_("josh").to("ripple").property(T.id,10).property("weight",1.0).addE("created").from_("josh").to("lop").property(T.id,11).property("weight",0.4).addE("created").from_("peter").to("lop").property(T.id,12).property("weight",0.2) }, function({g}) { return g.V().addV("animal").property("age",0) }, function({g}) { return g.V().has("animal","age",0) }], 
+    g_addVXpersonX_propertyXname_stephenX: [function({g}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","java").as("ripple").addV("person").property(T.id,6).property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property(T.id,7).property("weight",0.5).addE("knows").from_("marko").to("josh").property(T.id,8).property("weight",1.0).addE("created").from_("marko").to("lop").property(T.id,9).property("weight",0.4).addE("created").from_("josh").to("ripple").property(T.id,10).property("weight",1.0).addE("created").from_("josh").to("lop").property(T.id,11).property("weight",0.4).addE("created").from_("peter").to("lop").property(T.id,12).property("weight",0.2) }, function({g}) { return g.addV("person").property("name","stephen") }, function({g}) { return g.V().has("person","name","stephen") }], 
+    g_V_hasLabelXpersonX_propertyXname_nullX: [function({g}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","java").as("ripple").addV("person").property(T.id,6).property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property(T.id,7).property("weight",0.5).addE("knows").from_("marko").to("josh").property(T.id,8).property("weight",1.0).addE("created").from_("marko").to("lop").property(T.id,9).property("weight",0.4).addE("created").from_("josh").to("ripple").property(T.id,10).property("weight",1.0).addE("created").from_("josh").to("lop").property(T.id,11).property("weight",0.4).addE("created").from_("peter").to("lop").property(T.id,12).property("weight",0.2) }, function({g}) { return g.V().hasLabel("person").property("name",null) }, function({g}) { return g.V().properties("name") }], 
+    g_addVXpersonX_propertyXsingle_name_stephenX_propertyXsingle_name_stephenmX: [function({g}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","java").as("ripple").addV("person").property(T.id,6).property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property(T.id,7).property("weight",0.5).addE("knows").from_("marko").to("josh").property(T.id,8).property("weight",1.0).addE("created").from_("marko").to("lop").property(T.id,9).property("weight",0.4).addE("created").from_("josh").to("ripple").property(T.id,10).property("weight",1.0).addE("created").from_("josh").to("lop").property(T.id,11).property("weight",0.4).addE("created").from_("peter").to("lop").property(T.id,12).property("weight",0.2) }, function({g}) { return g.addV("person").property(Cardinality.single,"name","stephen").property(Cardinality.single,"name","stephenm") }, function({g}) { return g.V().has("person","name","stephen") }, function({g}) { return g.V().has("person","name","stephenm") }], 
+    get_g_addVXpersonX_propertyXsingle_name_stephenX_propertyXsingle_name_stephenm_since_2010X: [function({g}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","java").as("ripple").addV("person").property(T.id,6).property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property(T.id,7).property("weight",0.5).addE("knows").from_("marko").to("josh").property(T.id,8).property("weight",1.0).addE("created").from_("marko").to("lop").property(T.id,9).property("weight",0.4).addE("created").from_("josh").to("ripple").property(T.id,10).property("weight",1.0).addE("created").from_("josh").to("lop").property(T.id,11).property("weight",0.4).addE("created").from_("peter").to("lop").property(T.id,12).property("weight",0.2) }, function({g}) { return g.addV("person").property(Cardinality.single,"name","stephen").property(Cardinality.single,"name","stephenm","since",2010) }, function({g}) { return g.V().has("person","name","stephen") }, function({g}) { return g.V().has("person","name","stephenm") }, function({g}) { return g.V().has("person","name","stephenm").properties("name").has("since",2010) }], 
+    g_V_hasXname_markoX_propertyXfriendWeight_outEXknowsX_weight_sum__acl_privateX: [function({g}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","java").as("ripple").addV("person").property(T.id,6).property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property(T.id,7).property("weight",0.5).addE("knows").from_("marko").to("josh").property(T.id,8).property("weight",1.0).addE("created").from_("marko").to("lop").property(T.id,9).property("weight",0.4).addE("created").from_("josh").to("ripple").property(T.id,10).property("weight",1.0).addE("created").from_("josh").to("lop").property(T.id,11).property("weight",0.4).addE("created").from_("peter").to("lop").property(T.id,12).property("weight",0.2) }, function({g}) { return g.V().has("name","marko").property("friendWeight",__.outE("knows").values("weight").sum(),"acl","private") }, function({g}) { return g.V().has("person","name","marko").has("friendWeight",1.5) }, function({g}) { return g.V().has("person","name","marko").properties("friendWeight").has("acl","private") }, function({g}) { return g.V().has("person","name","marko").properties("friendWeight").count() }], 
+    g_addVXanimalX_propertyXname_mateoX_propertyXname_gateoX_propertyXname_cateoX_propertyXage_5X: [function({g}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","java").as("ripple").addV("person").property(T.id,6).property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property(T.id,7).property("weight",0.5).addE("knows").from_("marko").to("josh").property(T.id,8).property("weight",1.0).addE("created").from_("marko").to("lop").property(T.id,9).property("weight",0.4).addE("created").from_("josh").to("ripple").property(T.id,10).property("weight",1.0).addE("created").from_("josh").to("lop").property(T.id,11).property("weight",0.4).addE("created").from_("peter").to("lop").property(T.id,12).property("weight",0.2) }, function({g}) { return g.addV("animal").property("name","mateo").property("name","gateo").property("name","cateo").property("age",5) }, function({g}) { return g.V().hasLabel("animal").has("name","mateo").has("name","gateo").has("name","cateo").has("age",5) }], 
+    g_withSideEffectXa_markoX_addV_propertyXname_selectXaXX_name: [function({g}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","java").as("ripple").addV("person").property(T.id,6).property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property(T.id,7).property("weight",0.5).addE("knows").from_("marko").to("josh").property(T.id,8).property("weight",1.0).addE("created").from_("marko").to("lop").property(T.id,9).property("weight",0.4).addE("created").from_("josh").to("ripple").property(T.id,10).property("weight",1.0).addE("created").from_("josh").to("lop").property(T.id,11).property("weight",0.4).addE("created").from_("peter").to("lop").property(T.id,12).property("weight",0.2) }, function({g}) { return g.withSideEffect("a","marko").addV().property("name",__.select("a")).values("name") }, function({g}) { return g.V().has("name","marko") }], 
+    g_addVXpersonX_propertyXsingle_name_stephenX_propertyXsingle_name_stephenm_since_2010X: [function({g}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","java").as("ripple").addV("person").property(T.id,6).property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property(T.id,7).property("weight",0.5).addE("knows").from_("marko").to("josh").property(T.id,8).property("weight",1.0).addE("created").from_("marko").to("lop").property(T.id,9).property("weight",0.4).addE("created").from_("josh").to("ripple").property(T.id,10).property("weight",1.0).addE("created").from_("josh").to("lop").property(T.id,11).property("weight",0.4).addE("created").from_("peter").to("lop").property(T.id,12).property("weight",0.2) }, function({g}) { return g.addV("person").property(Cardinality.single,"name","stephen").property(Cardinality.single,"name","stephenm","since",2010) }, function({g}) { return g.V().has("name","stephen") }, function({g}) { return g.V().has("name","stephenm") }, function({g}) { return g.V().has("name","stephenm").properties("name").has("since",2010) }], 
+    g_V_addVXanimalX_propertyXname_valuesXnameXX_propertyXname_an_animalX_propertyXvaluesXnameX_labelX: [function({g}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","java").as("ripple").addV("person").property(T.id,6).property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property(T.id,7).property("weight",0.5).addE("knows").from_("marko").to("josh").property(T.id,8).property("weight",1.0).addE("created").from_("marko").to("lop").property(T.id,9).property("weight",0.4).addE("created").from_("josh").to("ripple").property(T.id,10).property("weight",1.0).addE("created").from_("josh").to("lop").property(T.id,11).property("weight",0.4).addE("created").from_("peter").to("lop").property(T.id,12).property("weight",0.2) }, function({g}) { return g.V().addV("animal").property("name",__.values("name")).property("name","an animal").property(__.values("name"),__.label()) }, function({g}) { return g.V().hasLabel("animal").has("name","marko").has("name","an animal").has("marko","person") }, function({g}) { return g.V().hasLabel("animal").has("name","vadas").has("name","an animal").has("vadas","person") }, function({g}) { return g.V().hasLabel("animal").has("name","lop").has("name","an animal").has("lop","software") }, function({g}) { return g.V().hasLabel("animal").has("name","josh").has("name","an animal").has("josh","person") }, function({g}) { return g.V().hasLabel("animal").has("name","ripple").has("name","an animal").has("ripple","software") }, function({g}) { return g.V().hasLabel("animal").has("name","peter").has("name","an animal").has("peter","person") }], 
+    g_withSideEffectXa_testX_V_hasLabelXsoftwareX_propertyXtemp_selectXaXX_valueMapXname_tempX: [function({g}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","java").as("ripple").addV("person").property(T.id,6).property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property(T.id,7).property("weight",0.5).addE("knows").from_("marko").to("josh").property(T.id,8).property("weight",1.0).addE("created").from_("marko").to("lop").property(T.id,9).property("weight",0.4).addE("created").from_("josh").to("ripple").property(T.id,10).property("weight",1.0).addE("created").from_("josh").to("lop").property(T.id,11).property("weight",0.4).addE("created").from_("peter").to("lop").property(T.id,12).property("weight",0.2) }, function({g}) { return g.withSideEffect("a","test").V().hasLabel("software").property("temp",__.select("a")).valueMap("name","temp") }], 
+    g_withSideEffectXa_nameX_addV_propertyXselectXaX_markoX_name: [function({g}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","java").as("ripple").addV("person").property(T.id,6).property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property(T.id,7).property("weight",0.5).addE("knows").from_("marko").to("josh").property(T.id,8).property("weight",1.0).addE("created").from_("marko").to("lop").property(T.id,9).property("weight",0.4).addE("created").from_("josh").to("ripple").property(T.id,10).property("weight",1.0).addE("created").from_("josh").to("lop").property(T.id,11).property("weight",0.4).addE("created").from_("peter").to("lop").property(T.id,12).property("weight",0.2) }, function({g}) { return g.withSideEffect("a","name").addV().property(__.select("a"),"marko").values("name") }, function({g}) { return g.V().has("name","marko") }], 
+    g_V_asXaX_hasXname_markoX_outXcreatedX_asXbX_addVXselectXaX_labelX_propertyXtest_selectXbX_labelX_valueMap_withXtokensX: [function({g}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","java").as("ripple").addV("person").property(T.id,6).property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property(T.id,7).property("weight",0.5).addE("knows").from_("marko").to("josh").property(T.id,8).property("weight",1.0).addE("created").from_("marko").to("lop").property(T.id,9).property("weight",0.4).addE("created").from_("josh").to("ripple").property(T.id,10).property("weight",1.0).addE("created").from_("josh").to("lop").property(T.id,11).property("weight",0.4).addE("created").from_("peter").to("lop").property(T.id,12).property("weight",0.2) }, function({g}) { return g.V().as("a").has("name","marko").out("created").as("b").addV(__.select("a").label()).property("test",__.select("b").label()).valueMap().with_("~tinkerpop.valueMap.tokens") }, function({g}) { return g.V().has("person","test","software") }], 
+    g_addVXV_hasXname_markoX_propertiesXnameX_keyX_label: [function({g}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","java").as("ripple").addV("person").property(T.id,6).property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property(T.id,7).property("weight",0.5).addE("knows").from_("marko").to("josh").property(T.id,8).property("weight",1.0).addE("created").from_("marko").to("lop").property(T.id,9).property("weight",0.4).addE("created").from_("josh").to("ripple").property(T.id,10).property("weight",1.0).addE("created").from_("josh").to("lop").property(T.id,11).property("weight",0.4).addE("created").from_("peter").to("lop").property(T.id,12).property("weight",0.2) }, function({g}) { return g.addV(__.V().has("name","marko").properties("name").key()).label() }], 
+    g_addVXnullX_propertyXid_nullX: [function({g}) { return g.addV(null).property(T.id,null) }, function({g}) { return g.V().hasLabel("vertex") }], 
+    g_addV_propertyXlabel_personX: [function({g}) { return g.addV().property(T.label,"person") }, function({g}) { return g.V().hasLabel("person") }], 
+    g_V_coalesceXoutXfooX_outXbarXX: [function({g}) { return g.V().coalesce(__.out("foo"),__.out("bar")) }], 
+    g_VX1X_coalesceXoutXknowsX_outXcreatedXX_valuesXnameX: [function({g, vid1}) { return g.V(vid1).coalesce(__.out("knows"),__.out("created")).values("name") }], 
+    g_VX1X_coalesceXoutXcreatedX_outXknowsXX_valuesXnameX: [function({g, vid1}) { return g.V(vid1).coalesce(__.out("created"),__.out("knows")).values("name") }], 
+    g_V_coalesceXoutXlikesX_outXknowsX_inXcreatedXX_groupCount_byXnameX: [function({g}) { return g.V().coalesce(__.out("likes"),__.out("knows"),__.out("created")).groupCount().by("name") }], 
+    g_V_coalesceXoutEXknowsX_outEXcreatedXX_otherV_path_byXnameX_byXlabelX: [function({g}) { return g.V().coalesce(__.outE("knows"),__.outE("created")).otherV().path().by("name").by(T.label) }], 
+    g_V_outXcreatedX_order_byXnameX_coalesceXname_constantXxXX: [function({g}) { return g.V().out("created").order().by("name").coalesce(__.values("name"),__.constant("x")) }], 
+    g_V_connectedComponent_hasXcomponentX: [function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().connectedComponent().has("gremlin.connectedComponentVertexProgram.component") }], 
+    g_V_dedup_connectedComponent_hasXcomponentX: [function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().dedup().connectedComponent().has("gremlin.connectedComponentVertexProgram.component") }], 
+    g_V_hasLabelXsoftwareX_connectedComponent_project_byXnameX_byXcomponentX: [function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().hasLabel("software").connectedComponent().project("name","component").by("name").by("gremlin.connectedComponentVertexProgram.component") }], 
+    g_V_connectedComponent_withXEDGES_bothEXknowsXX_withXPROPERTY_NAME_clusterX_project_byXnameX_byXclusterX: [function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().hasLabel("person").connectedComponent().with_("~tinkerpop.connectedComponent.edges",__.bothE("knows")).with_("~tinkerpop.connectedComponent.propertyName","cluster").project("name","cluster").by("name").by("cluster") }], 
+    g_V_constantX123X: [function({g}) { return g.V().constant(123) }], 
+    g_V_constantXnullX: [function({g}) { return g.V().constant(null) }], 
+    g_V_chooseXhasLabelXpersonX_valuesXnameX_constantXinhumanXX: [function({g}) { return g.V().choose(__.hasLabel("person"),__.values("name"),__.constant("inhuman")) }], 
+    g_V_count: [function({g}) { return g.V().count() }], 
+    g_V_out_count: [function({g}) { return g.V().out().count() }], 
+    g_V_both_both_count: [function({g}) { return g.V().both().both().count() }], 
+    g_V_fold_countXlocalX: [function({g}) { return g.V().fold().count(Scope.local) }], 
+    g_V_hasXnoX_count: [function({g}) { return g.V().has("no").count() }], 
+    g_V_whereXinXkknowsX_outXcreatedX_count_is_0XX_name: [function({g}) { return g.V().where(__.in_("knows").out("created").count().is(0)).values("name") }], 
+    g_V_repeatXoutX_timesX8X_count: [function({g}) { return g.V().repeat(__.out()).times(8).count() }], 
+    g_V_repeatXoutX_timesX5X_asXaX_outXwrittenByX_asXbX_selectXa_bX_count: [function({g}) { return g.V().repeat(__.out()).times(5).as("a").out("writtenBy").as("b").select("a","b").count() }], 
+    g_V_repeatXoutX_timesX3X_count: [function({g}) { return g.V().repeat(__.out()).times(3).count() }], 
+    g_V_elementMap: [function({g}) { return g.V().elementMap() }], 
+    g_V_elementMapXname_ageX: [function({g}) { return g.V().elementMap("name","age") }], 
+    g_EX11X_elementMap: [function({g, eid11}) { return g.E(eid11).elementMap() }], 
+    g_V_asXaX_flatMapXselectXaXX: [function({g}) { return g.V().as("a").flatMap(__.select("a")) }], 
+    g_V_fold: [function({g}) { return g.V().fold() }], 
+    g_V_fold_unfold: [function({g}) { return g.V().fold().unfold() }], 
+    g_V_age_foldX0_plusX: [function({g}) { return g.V().values("age").fold(0,Operator.sum) }], 
+    g_VX1X_V_valuesXnameX: [function({g, vid1}) { return g.V(vid1).V().values("name") }], 
+    g_V_outXknowsX_V_name: [function({g}) { return g.V().out("knows").V().values("name") }], 
+    g_V_hasXname_GarciaX_inXsungByX_asXsongX_V_hasXname_Willie_DixonX_inXwrittenByX_whereXeqXsongXX_name: [function({g}) { return g.V().has("artist","name","Garcia").in_("sungBy").as("song").V().has("artist","name","Willie_Dixon").in_("writtenBy").where(P.eq("song")).values("name") }], 
+    g_V_hasLabelXpersonX_asXpX_VXsoftwareX_addInEXuses_pX: [function({g, xx1, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","java").as("ripple").addV("person").property(T.id,6).property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property(T.id,7).property("weight",0.5).addE("knows").from_("marko").to("josh").property(T.id,8).property("weight",1.0).addE("created").from_("marko").to("lop").property(T.id,9).property("weight",0.4).addE("created").from_("josh").to("ripple").property(T.id,10).property("weight",1.0).addE("created").from_("josh").to("lop").property(T.id,11).property("weight",0.4).addE("created").from_("peter").to("lop").property(T.id,12).property("weight",0.2) }, function({g, xx1, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V().hasLabel("person").as("p").V(xx1).addE("uses").from_("p") }, function({g, xx1, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.E().hasLabel("uses") }, function({g, xx1, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid1).outE("uses") }, function({g, xx1, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid2).outE("uses") }, function({g, xx1, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid3).inE("uses") }, function({g, xx1, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid4).outE("uses") }, function({g, xx1, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid5).inE("uses") }, function({g, xx1, vid1, vid2, vid3, vid4, vid5, vid6}) { return g.V(vid6).outE("uses") }], 
+    g_V_hasLabelXsoftwareX_index_unfold: [function({g}) { return g.V().hasLabel("software").index().unfold() }], 
+    g_V_hasLabelXsoftwareX_order_byXnameX_index_withXmapX: [function({g}) { return g.V().hasLabel("software").order().by("name").index().with_("~tinkerpop.index.indexer",1) }], 
+    g_V_hasLabelXsoftwareX_name_fold_orderXlocalX_index_unfold_order_byXtailXlocal_1XX: [function({g}) { return g.V().hasLabel("software").values("name").fold().order(Scope.local).index().unfold().order().by(__.tail(Scope.local,1)) }], 
+    g_V_hasLabelXpersonX_name_fold_orderXlocalX_index_withXmapX: [function({g}) { return g.V().hasLabel("person").values("name").fold().order(Scope.local).index().with_("~tinkerpop.index.indexer",1) }], 
+    g_VX1X_repeatXboth_simplePathX_untilXhasXname_peterX_or_loops_isX3XX_hasXname_peterX_path_byXnameX: [function({g, vid1}) { return g.V(vid1).repeat(__.both().simplePath()).until(__.has("name","peter").or().loops().is(3)).has("name","peter").path().by("name") }], 
+    g_VX1X_repeatXboth_simplePathX_untilXhasXname_peterX_or_loops_isX2XX_hasXname_peterX_path_byXnameX: [function({g, vid1}) { return g.V(vid1).repeat(__.both().simplePath()).until(__.has("name","peter").or().loops().is(2)).has("name","peter").path().by("name") }], 
+    g_VX1X_repeatXboth_simplePathX_untilXhasXname_peterX_and_loops_isX3XX_hasXname_peterX_path_byXnameX: [function({g, vid1}) { return g.V(vid1).repeat(__.both().simplePath()).until(__.has("name","peter").and().loops().is(3)).has("name","peter").path().by("name") }], 
+    g_V_emitXhasXname_markoX_or_loops_isX2XX_repeatXoutX_valuesXnameX: [function({g}) { return g.V().emit(__.has("name","marko").or().loops().is(2)).repeat(__.out()).values("name") }], 
+    g_VX1X_mapXnameX: [function({g, l1, vid1}) { return g.V(vid1).map(l1) }], 
+    g_VX1X_outE_label_mapXlengthX: [function({g, l1, vid1}) { return g.V(vid1).outE().label().map(l1) }], 
+    g_VX1X_out_mapXnameX_mapXlengthX: [function({g, l1, l2, vid1}) { return g.V(vid1).out().map(l1).map(l2) }], 
+    g_VX1X_out_mapXlambdaXnameXX_mapXlambdaXlengthXX: [function({g, vid1}) { return g.V(vid1).out().map(() => "it.get().value(\'name\')").map(() => "it.get().toString().length()") }], 
+    g_withPath_V_asXaX_out_mapXa_nameX: [function({g, l1}) { return g.withPath().V().as("a").out().map(l1) }], 
+    g_withPath_V_asXaX_out_out_mapXa_name_it_nameX: [function({g, l1}) { return g.withPath().V().as("a").out().out().map(l1) }], 
+    g_V_mapXselectXaXX: [function({g}) { return g.V().as("a").map(__.select("a")) }], 
+    g_V_mapXconstantXnullXX: [function({g}) { return g.V().map(__.constant(null)) }], 
+    g_V_valueMap_matchXa_selectXnameX_bX: [function({g}) { return g.V().valueMap().match(__.as("a").select("name").as("b")) }], 
+    g_V_matchXa_out_bX: [function({g}) { return g.V().match(__.as("a").out().as("b")) }], 
+    g_V_matchXa_out_bX_selectXb_idX: [function({g}) { return g.V().match(__.as("a").out().as("b")).select("b").by(T.id) }], 
+    g_V_matchXa_knows_b__b_created_cX: [function({g}) { return g.V().match(__.as("a").out("knows").as("b"),__.as("b").out("created").as("c")) }], 
+    g_V_matchXb_created_c__a_knows_bX: [function({g}) { return g.V().match(__.as("b").out("created").as("c"),__.as("a").out("knows").as("b")) }], 
+    g_V_matchXa_created_b__b_0created_cX_whereXa_neq_cX_selectXa_cX: [function({g}) { return g.V().match(__.as("a").out("created").as("b"),__.as("b").in_("created").as("c")).where("a",P.neq("c")).select("a","c") }], 
+    g_V_matchXd_0knows_a__d_hasXname_vadasX__a_knows_b__b_created_cX: [function({g}) { return g.V().match(__.as("d").in_("knows").as("a"),__.as("d").has("name","vadas"),__.as("a").out("knows").as("b"),__.as("b").out("created").as("c")) }], 
+    g_V_matchXa_created_lop_b__b_0created_29_c__c_whereXrepeatXoutX_timesX2XXX: [function({g}) { return g.V().match(__.as("a").out("created").has("name","lop").as("b"),__.as("b").in_("created").has("age",29).as("c"),__.as("c").where(__.repeat(__.out()).times(2))) }], 
+    g_V_asXaX_out_asXbX_matchXa_out_count_c__b_in_count_cX: [function({g}) { return g.V().as("a").out().as("b").match(__.as("a").out().count().as("c"),__.as("b").in_().count().as("c")) }], 
+    g_V_matchXa__a_out_b__notXa_created_bXX: [function({g}) { return g.V().match(__.as("a").out().as("b"),__.not(__.as("a").out("created").as("b"))) }], 
+    g_V_matchXa_created_lop_b__b_0created_29_cX_whereXc_repeatXoutX_timesX2XX_selectXa_b_cX: [function({g}) { return g.V().match(__.as("a").out("created").has("name","lop").as("b"),__.as("b").in_("created").has("age",29).as("c")).where(__.as("c").repeat(__.out()).times(2)).select("a","b","c") }], 
+    g_V_out_out_matchXa_0created_b__b_0knows_cX_selectXcX_outXcreatedX_name: [function({g}) { return g.V().out().out().match(__.as("a").in_("created").as("b"),__.as("b").in_("knows").as("c")).select("c").out("created").values("name") }], 
+    g_V_matchXa_knows_b__b_created_c__a_created_cX_dedupXa_b_cX_selectXaX_byXnameX: [function({g}) { return g.V().match(__.as("a").out("knows").as("b"),__.as("b").out("created").as("c"),__.as("a").out("created").as("c")).dedup("a","b","c").select("a").by("name") }], 
+    g_V_matchXa_created_b__a_repeatXoutX_timesX2XX_selectXa_bX: [function({g}) { return g.V().match(__.as("a").out("created").as("b"),__.as("a").repeat(__.out()).times(2).as("b")).select("a","b") }], 
+    g_V_notXmatchXa_age_b__a_name_cX_whereXb_eqXcXX_selectXaXX_name: [function({g}) { return g.V().not(__.match(__.as("a").values("age").as("b"),__.as("a").values("name").as("c")).where("b",P.eq("c")).select("a")).values("name") }], 
+    g_V_matchXa_knows_b__andXa_created_c__b_created_c__andXb_created_count_d__a_knows_count_dXXX: [function({g}) { return g.V().match(__.as("a").out("knows").as("b"),__.and(__.as("a").out("created").as("c"),__.as("b").out("created").as("c"),__.and(__.as("b").out("created").count().as("d"),__.as("a").out("knows").count().as("d")))) }], 
+    g_V_matchXa_whereXa_neqXcXX__a_created_b__orXa_knows_vadas__a_0knows_and_a_hasXlabel_personXX__b_0created_c__b_0created_count_isXgtX1XXX_selectXa_b_cX_byXidX: [function({g}) { return g.V().match(__.where("a",P.neq("c")),__.as("a").out("created").as("b"),__.or(__.as("a").out("knows").has("name","vadas"),__.as("a").in_("knows").and().as("a").has(T.label,"person")),__.as("b").in_("created").as("c"),__.as("b").in_("created").count().is(P.gt(1))).select("a","b","c").by(T.id) }], 
+    g_V_matchXa__a_both_b__b_both_cX_dedupXa_bX: [function({g}) { return g.V().match(__.as("a").both().as("b"),__.as("b").both().as("c")).dedup("a","b") }], 
+    g_V_matchXa_knows_b__b_created_lop__b_matchXb_created_d__d_0created_cX_selectXcX_cX_selectXa_b_cX: [function({g}) { return g.V().match(__.as("a").out("knows").as("b"),__.as("b").out("created").has("name","lop"),__.as("b").match(__.as("b").out("created").as("d"),__.as("d").in_("created").as("c")).select("c").as("c")).select("a","b","c") }], 
+    g_V_matchXa_knows_b__a_created_cX: [function({g}) { return g.V().match(__.as("a").out("knows").as("b"),__.as("a").out("created").as("c")) }], 
+    g_V_matchXwhereXandXa_created_b__b_0created_count_isXeqX3XXXX__a_both_b__whereXb_inXX: [function({g}) { return g.V().match(__.where(__.and(__.as("a").out("created").as("b"),__.as("b").in_("created").count().is(P.eq(3)))),__.as("a").both().as("b"),__.where(__.as("b").in_())) }], 
+    g_V_matchXa_outEXcreatedX_order_byXweight_descX_limitX1X_inV_b__b_hasXlang_javaXX_selectXa_bX_byXnameX: [function({g}) { return g.V().match(__.as("a").outE("created").order().by("weight",Order.desc).limit(1).inV().as("b"),__.as("b").has("lang","java")).select("a","b").by("name") }], 
+    g_V_matchXa_both_b__b_both_cX_dedupXa_bX_byXlabelX: [function({g}) { return g.V().match(__.as("a").both().as("b"),__.as("b").both().as("c")).dedup("a","b").by(T.label) }], 
+    g_V_matchXa_created_b__b_0created_aX: [function({g}) { return g.V().match(__.as("a").out("created").as("b"),__.as("b").in_("created").as("a")) }], 
+    g_V_asXaX_out_asXbX_matchXa_out_count_c__orXa_knows_b__b_in_count_c__and__c_isXgtX2XXXX: [function({g}) { return g.V().as("a").out().as("b").match(__.as("a").out().count().as("c"),__.or(__.as("a").out("knows").as("b"),__.as("b").in_().count().as("c").and().as("c").is(P.gt(2)))) }], 
+    g_V_matchXa_knows_count_bX_selectXbX: [function({g}) { return g.V().match(__.as("a").out("knows").count().as("b")).select("b") }], 
+    g_V_matchXa_0sungBy_b__a_0writtenBy_c__b_writtenBy_d__c_sungBy_d__d_hasXname_GarciaXX: [function({g}) { return g.V().match(__.as("a").in_("sungBy").as("b"),__.as("a").in_("writtenBy").as("c"),__.as("b").out("writtenBy").as("d"),__.as("c").out("sungBy").as("d"),__.as("d").has("name","Garcia")) }], 
+    g_V_matchXa_hasXsong_name_sunshineX__a_mapX0followedBy_weight_meanX_b__a_0followedBy_c__c_filterXweight_whereXgteXbXXX_outV_dX_selectXdX_byXnameX: [function({g}) { return g.V().match(__.as("a").has("song","name","HERE COMES SUNSHINE"),__.as("a").map(__.inE("followedBy").values("weight").mean()).as("b"),__.as("a").inE("followedBy").as("c"),__.as("c").filter(__.values("weight").where(P.gte("b"))).outV().as("d")).select("d").by("name") }], 
+    g_V_matchXa_0sungBy_b__a_0sungBy_c__b_writtenBy_d__c_writtenBy_e__d_hasXname_George_HarisonX__e_hasXname_Bob_MarleyXX: [function({g}) { return g.V().match(__.as("a").in_("sungBy").as("b"),__.as("a").in_("sungBy").as("c"),__.as("b").out("writtenBy").as("d"),__.as("c").out("writtenBy").as("e"),__.as("d").has("name","George_Harrison"),__.as("e").has("name","Bob_Marley")) }], 
+    g_V_matchXa_hasXname_GarciaX__a_0writtenBy_b__a_0sungBy_bX: [function({g}) { return g.V().match(__.as("a").has("name","Garcia"),__.as("a").in_("writtenBy").as("b"),__.as("a").in_("sungBy").as("b")) }], 
+    g_V_hasLabelXsongsX_matchXa_name_b__a_performances_cX_selectXb_cX_count: [function({g}) { return g.V().hasLabel("song").match(__.as("a").values("name").as("b"),__.as("a").values("performances").as("c")).select("b","c").count() }], 
+    g_V_matchXa_followedBy_count_isXgtX10XX_b__a_0followedBy_count_isXgtX10XX_bX_count: [function({g}) { return g.V().match(__.as("a").out("followedBy").count().is(P.gt(10)).as("b"),__.as("a").in_("followedBy").count().is(P.gt(10)).as("b")).count() }], 
+    g_V_matchXa_0sungBy_b__a_0writtenBy_c__b_writtenBy_dX_whereXc_sungBy_dX_whereXd_hasXname_GarciaXX: [function({g}) { return g.V().match(__.as("a").in_("sungBy").as("b"),__.as("a").in_("writtenBy").as("c"),__.as("b").out("writtenBy").as("d")).where(__.as("c").out("sungBy").as("d")).where(__.as("d").has("name","Garcia")) }], 
+    g_V_matchXa_hasXname_GarciaX__a_0writtenBy_b__b_followedBy_c__c_writtenBy_d__whereXd_neqXaXXX: [function({g}) { return g.V().match(__.as("a").has("name","Garcia"),__.as("a").in_("writtenBy").as("b"),__.as("b").out("followedBy").as("c"),__.as("c").out("writtenBy").as("d"),__.where("d",P.neq("a"))) }], 
+    g_V_matchXa_outXknowsX_name_bX_identity: [function({g}) { return g.V().match(__.as("a").out("knows").values("name").as("b")).identity() }], 
+    g_V_outE_mathX0_minus_itX_byXweightX: [function({g}) { return g.V().outE().math("0-_").by("weight") }], 
+    g_V_hasXageX_valueMap_mathXit_plus_itXbyXselectXageX_unfoldXX: [function({g}) { return g.V().has("age").valueMap().math("_+_").by(__.select("age").unfold()) }], 
+    g_V_asXaX_outXknowsX_asXbX_mathXa_plus_bX_byXageX: [function({g}) { return g.V().as("a").out("knows").as("b").math("a + b").by("age") }], 
+    g_withSideEffectXx_100X_V_age_mathX__plus_xX: [function({g, xx1}) { return g.withSideEffect("x",xx1).V().values("age").math("_ + x") }], 
+    g_V_asXaX_outXcreatedX_asXbX_mathXb_plus_aX_byXinXcreatedX_countX_byXageX: [function({g}) { return g.V().as("a").out("created").as("b").math("b + a").by(__.in_("created").count()).by("age") }], 
+    g_withSackX1X_injectX1X_repeatXsackXsumX_byXconstantX1XXX_timesX5X_emit_mathXsin__X_byXsackX: [function({g}) { return g.withSack(1).inject(1).repeat(__.sack(Operator.sum).by(__.constant(1))).times(5).emit().math("sin _").by(__.sack()) }], 
+    g_V_projectXa_b_cX_byXbothE_weight_sumX_byXbothE_countX_byXnameX_order_byXmathXa_div_bX_descX_selectXcX: [function({g}) { return g.V().project("a","b","c").by(__.bothE().values("weight").sum()).by(__.bothE().count()).by("name").order().by(__.math("a / b"),Order.desc).select("c") }], 
+    g_V_age_max: [function({g}) { return g.V().values("age").max() }], 
+    g_V_foo_max: [function({g}) { return g.V().values("foo").max() }], 
+    g_V_name_max: [function({g}) { return g.V().values("name").max() }], 
+    g_V_age_fold_maxXlocalX: [function({g}) { return g.V().values("age").fold().max(Scope.local) }], 
+    g_V_foo_fold_maxXlocalX: [function({g}) { return g.V().values("foo").fold().max(Scope.local) }], 
+    g_V_name_fold_maxXlocalX: [function({g}) { return g.V().values("name").fold().max(Scope.local) }], 
+    g_V_repeatXbothX_timesX5X_age_max: [function({g}) { return g.V().repeat(__.both()).times(5).values("age").max() }], 
+    g_V_hasLabelXsoftwareX_group_byXnameX_byXbothE_weight_maxX: [function({g}) { return g.V().hasLabel("software").group().by("name").by(__.bothE().values("weight").max()) }], 
+    g_V_age_mean: [function({g}) { return g.V().values("age").mean() }], 
+    g_V_foo_mean: [function({g}) { return g.V().values("foo").mean() }], 
+    g_V_age_fold_meanXlocalX: [function({g}) { return g.V().values("age").fold().mean(Scope.local) }], 
+    g_V_foo_fold_meanXlocalX: [function({g}) { return g.V().values("foo").fold().mean(Scope.local) }], 
+    g_V_hasLabelXsoftwareX_group_byXnameX_byXbothE_weight_meanX: [function({g}) { return g.V().hasLabel("software").group().by("name").by(__.bothE().values("weight").mean()) }], 
+    g_V_age_min: [function({g}) { return g.V().values("age").min() }], 
+    g_V_foo_min: [function({g}) { return g.V().values("foo").min() }], 
+    g_V_name_min: [function({g}) { return g.V().values("name").min() }], 
+    g_V_age_fold_minXlocalX: [function({g}) { return g.V().values("age").fold().min(Scope.local) }], 
+    g_V_foo_fold_minXlocalX: [function({g}) { return g.V().values("foo").fold().min(Scope.local) }], 
+    g_V_name_fold_minXlocalX: [function({g}) { return g.V().values("name").fold().min(Scope.local) }], 
+    g_V_repeatXbothX_timesX5X_age_min: [function({g}) { return g.V().repeat(__.both()).times(5).values("age").min() }], 
+    g_V_hasLabelXsoftwareX_group_byXnameX_byXbothE_weight_minX: [function({g}) { return g.V().hasLabel("software").group().by("name").by(__.bothE().values("weight").min()) }], 
+    g_V_foo_injectX9999999999X_min: [function({g, xx1}) { return g.V().values("foo").inject(xx1).min() }], 
+    g_V_name_order: [function({g}) { return g.V().values("name").order() }], 
+    g_V_name_order_byXa1_b1X_byXb2_a2X: [function({g, c1, c2}) { return g.V().values("name").order().by(c1).by(c2) }], 
+    g_V_order_byXname_ascX_name: [function({g}) { return g.V().order().by("name",Order.asc).values("name") }], 
+    g_V_order_byXnameX_name: [function({g}) { return g.V().order().by("name").values("name") }], 
+    g_V_outE_order_byXweight_descX_weight: [function({g}) { return g.V().outE().order().by("weight",Order.desc).values("weight") }], 
+    g_V_order_byXname_a1_b1X_byXname_b2_a2X_name: [function({g, c1, c2}) { return g.V().order().by("name",c1).by("name",c2).values("name") }], 
+    g_V_asXaX_outXcreatedX_asXbX_order_byXshuffleX_selectXa_bX: [function({g}) { return g.V().as("a").out("created").as("b").order().by(Order.shuffle).select("a","b") }], 
+    g_V_both_hasLabelXpersonX_order_byXage_descX_limitX5X_name: [function({g}) { return g.V().both().hasLabel("person").order().by("age",Order.desc).limit(5).values("name") }], 
+    g_V_properties_order_byXkey_descX_key: [function({g}) { return g.V().properties().order().by(T.key,Order.desc).key() }], 
+    g_V_hasLabelXpersonX_order_byXvalueXageX_descX_name: [function({g, l1}) { return g.V().hasLabel("person").order().by(l1,Order.desc).values("name") }], 
+    g_V_hasLabelXpersonX_group_byXnameX_byXoutE_weight_sumX_orderXlocalX_byXvaluesX: [function({g}) { return g.V().hasLabel("person").group().by("name").by(__.outE().values("weight").sum()).order(Scope.local).by(Column.values) }], 
+    g_V_mapXbothE_weight_foldX_order_byXsumXlocalX_descX: [function({g}) { return g.V().map(__.bothE().values("weight").fold()).order().by(__.sum(Scope.local),Order.desc) }], 
+    g_V_group_byXlabelX_byXname_order_byXdescX_foldX: [function({g}) { return g.V().group().by(T.label).by(__.values("name").order().by(Order.desc).fold()) }], 
+    g_V_hasLabelXpersonX_group_byXnameX_byXoutE_weight_sumX_unfold_order_byXvalues_descX: [function({g}) { return g.V().hasLabel("person").group().by("name").by(__.outE().values("weight").sum()).unfold().order().by(Column.values,Order.desc) }], 
+    g_V_asXvX_mapXbothE_weight_foldX_sumXlocalX_asXsX_selectXv_sX_order_byXselectXsX_descX: [function({g}) { return g.V().as("v").map(__.bothE().values("weight").fold()).sum(Scope.local).as("s").select("v","s").order().by(__.select("s"),Order.desc) }], 
+    g_V_hasLabelXpersonX_fold_orderXlocalX_byXageX: [function({g}) { return g.V().hasLabel("person").fold().order(Scope.local).by("age") }], 
+    g_V_both_hasLabelXpersonX_order_byXage_descX_name: [function({g}) { return g.V().both().hasLabel("person").order().by("age",Order.desc).values("name") }], 
+    g_V_order_byXoutE_count_descX: [function({g}) { return g.V().order().by(__.outE().count(),Order.desc) }], 
+    g_V_hasLabelXpersonX_order_byXageX: [function({g}) { return g.V().hasLabel("person").order().by("age") }], 
+    g_VX1X_hasXlabel_personX_mapXmapXint_ageXX_orderXlocalX_byXvalues_descX_byXkeys_ascX: [function({g, l1, v1}) { return g.V(v1).hasLabel("person").map(l1).order(Scope.local).by(Column.values,Order.desc).by(Column.keys,Order.asc) }], 
+    g_VX1X_elementMap_orderXlocalX_byXkeys_descXunfold: [function({g, vid1}) { return g.V(vid1).elementMap().order(Scope.local).by(Column.keys,Order.desc).unfold() }], 
+    g_V_pageRank_hasXpageRankX: [function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().pageRank().has("gremlin.pageRankVertexProgram.pageRank") }, function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().pageRank().has("gremlin.pageRankVertexProgram.pageRank") }], 
+    g_V_outXcreatedX_pageRank_withXedges_bothEX_withXpropertyName_projectRankX_withXtimes_0X_valueMapXname_projectRankX: [function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().out("created").pageRank().with_("~tinkerpop.pageRank.edges",__.bothE()).with_("~tinkerpop.pageRank.propertyName","projectRank").with_("~tinkerpop.pageRank.times",0).valueMap("name","projectRank") }], 
+    g_V_pageRank_order_byXpageRank_descX_byXnameX_name: [function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().pageRank().order().by("gremlin.pageRankVertexProgram.pageRank",Order.desc).by("name").values("name") }], 
+    g_V_pageRank_order_byXpageRank_descX_name_limitX2X: [function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().pageRank().order().by("gremlin.pageRankVertexProgram.pageRank",Order.desc).values("name").limit(2) }], 
+    g_V_pageRank_withXedges_outEXknowsXX_withXpropertyName_friendRankX_project_byXnameX_byXvaluesXfriendRankX_mathX: [function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().pageRank().with_("~tinkerpop.pageRank.edges",__.outE("knows")).with_("~tinkerpop.pageRank.propertyName","friendRank").project("name","friendRank").by("name").by(__.values("friendRank").math("ceil(_ * 100)")) }], 
+    g_V_hasLabelXpersonX_pageRank_withXpropertyName_kpageRankX_project_byXnameX_byXvaluesXpageRankX_mathX: [function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().hasLabel("person").pageRank().with_("~tinkerpop.pageRank.propertyName","pageRank").project("name","pageRank").by("name").by(__.values("pageRank").math("ceil(_ * 100)")) }], 
+    g_V_pageRank_withXpropertyName_pageRankX_asXaX_outXknowsX_pageRank_asXbX_selectXa_bX_by_byXmathX: [function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().pageRank().with_("~tinkerpop.pageRank.propertyName","pageRank").as("a").out("knows").values("pageRank").as("b").select("a","b").by().by(__.math("ceil(_ * 100)")) }], 
+    g_V_hasLabelXsoftwareX_hasXname_rippleX_pageRankX1X_withXedges_inEXcreatedX_withXtimes_1X_withXpropertyName_priorsX_inXcreatedX_unionXboth__identityX_valueMapXname_priorsX: [function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().hasLabel("software").has("name","ripple").pageRank(1.0).with_("~tinkerpop.pageRank.edges",__.inE("created")).with_("~tinkerpop.pageRank.times",1).with_("~tinkerpop.pageRank.propertyName","priors").in_("created").union(__.both(),__.identity()).valueMap("name","priors") }], 
+    g_V_outXcreatedX_groupXmX_byXlabelX_pageRankX1X_withXpropertyName_pageRankX_withXedges_inEX_withXtimes_1X_inXcreatedX_groupXmX_byXpageRankX_capXmX: [function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().out("created").group("m").by(T.label).pageRank(1.0).with_("~tinkerpop.pageRank.propertyName","pageRank").with_("~tinkerpop.pageRank.edges",__.inE()).with_("~tinkerpop.pageRank.times",1).in_("created").group("m").by("pageRank").cap("m") }], 
+    g_VX1X_name_path: [function({g, vid1}) { return g.V(vid1).values("name").path() }], 
+    g_VX1X_out_path_byXageX_byXnameX: [function({g, vid1}) { return g.V(vid1).out().path().by("age").by("name") }], 
+    g_V_repeatXoutX_timesX2X_path_byXitX_byXnameX_byXlangX: [function({g}) { return g.V().repeat(__.out()).times(2).path().by().by("name").by("lang") }], 
+    g_V_out_out_path_byXnameX_byXageX: [function({g}) { return g.V().out().out().path().by("name").by("age") }], 
+    g_V_asXaX_hasXname_markoX_asXbX_hasXage_29X_asXcX_path: [function({g}) { return g.V().as("a").has("name","marko").as("b").has("age",29).as("c").path() }], 
+    g_VX1X_outEXcreatedX_inV_inE_outV_path: [function({g, vid1}) { return g.V(vid1).outE("created").inV().inE().outV().path() }], 
+    g_V_asXaX_out_asXbX_out_asXcX_path_fromXbX_toXcX_byXnameX: [function({g}) { return g.V().as("a").out().as("b").out().as("c").path().from_("b").to("c").by("name") }], 
+    g_V_peerPressure_hasXclusterX: [function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().peerPressure().has("gremlin.peerPressureVertexProgram.cluster") }, function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().peerPressure().has("gremlin.peerPressureVertexProgram.cluster") }], 
+    g_V_peerPressure_withXpropertyName_clusterX_withXedges_outEXknowsXX_pageRankX1X_byXrankX_withXedges_outEXknowsX_withXtimes_2X_group_byXclusterX_byXrank_sumX_limitX100X: [function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().peerPressure().with_("~tinkerpop.peerPressure.propertyName","cluster").with_("~tinkerpop.peerPressure.edges",__.outE("knows")).pageRank(1.0).with_("~tinkerpop.pageRank.propertyName","rank").with_("~tinkerpop.pageRank.edges",__.outE("knows")).with_("~tinkerpop.pageRank.times",1).group().by("cluster").by(__.values("rank").sum()).limit(100) }], 
+    g_V_hasXname_rippleX_inXcreatedX_peerPressure_withXedges_outEX_withyXpropertyName_clusterX_repeatXunionXidentity__bothX_timesX2X_dedup_valueMapXname_clusterX: [function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().has("name","ripple").in_("created").peerPressure().with_("~tinkerpop.peerPressure.edges",__.outE()).with_("~tinkerpop.peerPressure.propertyName","cluster").repeat(__.union(__.identity(),__.both())).times(2).dedup().valueMap("name","cluster") }], 
+    g_V_hasLabelXpersonX_projectXa_bX_byXoutE_countX_byXageX: [function({g}) { return g.V().hasLabel("person").project("a","b").by(__.outE().count()).by("age") }], 
+    g_V_outXcreatedX_projectXa_bX_byXnameX_byXinXcreatedX_countX_order_byXselectXbX__descX_selectXaX: [function({g}) { return g.V().out("created").project("a","b").by("name").by(__.in_("created").count()).order().by(__.select("b"),Order.desc).select("a") }], 
+    g_V_valueMap_projectXxX_byXselectXnameXX: [function({g}) { return g.V().valueMap().project("x").by(__.select("name")) }], 
+    g_V_hasXageX_propertiesXnameX: [function({g}) { return g.V().has("age").properties("name").value() }], 
+    g_V_hasXageX_propertiesXname_ageX_value: [function({g}) { return g.V().has("age").properties("name","age").value() }], 
+    g_V_hasXageX_propertiesXage_nameX_value: [function({g}) { return g.V().has("age").properties("age","name").value() }], 
+    get_g_VX1X_asXaX_outXknowsX_asXbX_selectXa_bX: [function({g, vid1}) { return g.V(vid1).as("a").out("knows").as("b").select("a","b") }], 
+    g_VX1X_asXaX_outXknowsX_asXbX_selectXa_bX_byXnameX: [function({g, vid1}) { return g.V(vid1).as("a").out("knows").as("b").select("a","b").by("name") }], 
+    g_VX1X_asXaX_outXknowsX_asXbX_selectXaX: [function({g, vid1}) { return g.V(vid1).as("a").out("knows").as("b").select("a") }], 
+    g_VX1X_asXaX_outXknowsX_asXbX_selectXaX_byXnameX: [function({g, vid1}) { return g.V(vid1).as("a").out("knows").as("b").select("a").by("name") }], 
+    g_V_asXaX_out_asXbX_selectXa_bX_byXnameX: [function({g}) { return g.V().as("a").out().as("b").select("a","b").by("name") }], 
+    g_V_asXaX_out_aggregateXxX_asXbX_selectXa_bX_byXnameX: [function({g}) { return g.V().as("a").out().aggregate("x").as("b").select("a","b").by("name") }], 
+    g_V_asXaX_name_order_asXbX_selectXa_bX_byXnameX_by_XitX: [function({g}) { return g.V().as("a").values("name").order().as("b").select("a","b").by("name").by() }], 
+    g_V_hasXname_gremlinX_inEXusesX_order_byXskill_ascX_asXaX_outV_asXbX_selectXa_bX_byXskillX_byXnameX: [function({g}) { return g.V().has("name","gremlin").inE("uses").order().by("skill",Order.asc).as("a").outV().as("b").select("a","b").by("skill").by("name") }], 
+    g_V_hasXname_isXmarkoXX_asXaX_selectXaX: [function({g}) { return g.V().has("name",__.is("marko")).as("a").select("a") }], 
+    g_V_label_groupCount_asXxX_selectXxX: [function({g}) { return g.V().label().groupCount().as("x").select("x") }], 
+    g_V_hasLabelXpersonX_asXpX_mapXbothE_label_groupCountX_asXrX_selectXp_rX: [function({g}) { return g.V().hasLabel("person").as("p").map(__.bothE().label().groupCount()).as("r").select("p","r") }], 
+    g_V_chooseXoutE_count_isX0X__asXaX__asXbXX_chooseXselectXaX__selectXaX__selectXbXX: [function({g, xx1}) { return g.V().choose(__.outE().count().is(xx1),__.as("a"),__.as("b")).choose(__.select("a"),__.select("a"),__.select("b")) }], 
+    g_VX1X_groupXaX_byXconstantXaXX_byXnameX_selectXaX_selectXaX: [function({g, vid1}) { return g.V(vid1).group("a").by(__.constant("a")).by(__.values("name")).barrier().select("a").select("a") }], 
+    g_VX1X_asXhereX_out_selectXhereX: [function({g, vid1}) { return g.V(vid1).as("here").out().select("here") }], 
+    g_VX4X_out_asXhereX_hasXlang_javaX_selectXhereX: [function({g, vid4}) { return g.V(vid4).as("here").out().select("here") }], 
+    g_VX4X_out_asXhereX_hasXlang_javaX_selectXhereX_name: [function({g, vid4}) { return g.V(vid4).out().as("here").has("lang","java").select("here").values("name") }], 
+    g_VX1X_outE_asXhereX_inV_hasXname_vadasX_selectXhereX: [function({g, vid1}) { return g.V(vid1).outE().as("here").inV().has("name","vadas").select("here") }], 
+    g_VX1X_outEXknowsX_hasXweight_1X_asXhereX_inV_hasXname_joshX_selectXhereX: [function({g, vid1}) { return g.V(vid1).outE("knows").has("weight",1.0).as("here").inV().has("name","josh").select("here") }], 
+    g_VX1X_outEXknowsX_asXhereX_hasXweight_1X_asXfakeX_inV_hasXname_joshX_selectXhereX: [function({g, vid1}) { return g.V(vid1).outE("knows").as("here").has("weight",1.0).as("fake").inV().has("name","josh").select("here") }], 
+    g_V_asXhereXout_name_selectXhereX: [function({g}) { return g.V().as("here").out().values("name").select("here") }], 
+    g_V_outXcreatedX_unionXasXprojectX_inXcreatedX_hasXname_markoX_selectXprojectX__asXprojectX_inXcreatedX_inXknowsX_hasXname_markoX_selectXprojectXX_groupCount_byXnameX: [function({g}) { return g.V().out("created").union(__.as("project").in_("created").has("name","marko").select("project"),__.as("project").in_("created").in_("knows").has("name","marko").select("project")).groupCount().by("name") }], 
+    g_V_untilXout_outX_repeatXin_asXaXX_selectXaX_byXtailXlocalX_nameX: [function({g}) { return g.V().until(__.out().out()).repeat(__.in_().as("a")).select("a").by(__.tail(Scope.local).values("name")) }], 
+    g_V_outE_weight_groupCount_selectXkeysX_unfold: [function({g}) { return g.V().outE().values("weight").groupCount().select(Column.keys).unfold() }], 
+    g_V_hasLabelXsoftwareX_asXnameX_asXlanguageX_asXcreatorsX_selectXname_language_creatorsX_byXnameX_byXlangX_byXinXcreatedX_name_fold_orderXlocalXX: [function({g}) { return g.V().hasLabel("software").as("name").as("language").as("creators").select("name","language","creators").by("name").by("lang").by(__.in_("created").values("name").fold().order(Scope.local)) }], 
+    g_V_outE_weight_groupCount_unfold_selectXkeysX_unfold: [function({g}) { return g.V().outE().values("weight").groupCount().unfold().select(Column.keys).unfold() }], 
+    g_V_outE_weight_groupCount_unfold_selectXvaluesX_unfold: [function({g}) { return g.V().outE().values("weight").groupCount().unfold().select(Column.values).unfold() }], 
+    g_V_untilXout_outX_repeatXin_asXaX_in_asXbXX_selectXa_bX_byXnameX: [function({g}) { return g.V().until(__.out().out()).repeat(__.in_().as("a").in_().as("b")).select("a","b").by("name") }], 
+    g_V_outE_weight_groupCount_selectXvaluesX_unfold: [function({g}) { return g.V().outE().values("weight").groupCount().select(Column.values).unfold() }], 
+    g_VX1X_asXaX_outXknowsX_asXbX_selectXa_bX: [function({g, vid1}) { return g.V(vid1).as("a").out("knows").as("b").select("a","b") }], 
+    g_V_asXaX_whereXoutXknowsXX_selectXaX: [function({g}) { return g.V().as("a").where(__.out("knows")).select("a") }], 
+    g_VX1X_asXaX_repeatXout_asXaXX_timesX2X_selectXfirst_aX: [function({g, vid1}) { return g.V(vid1).as("a").repeat(__.out().as("a")).times(2).select(Pop.first,"a") }], 
+    g_V_asXaX_outXknowsX_asXbX_localXselectXa_bX_byXnameXX: [function({g}) { return g.V().as("a").out("knows").as("b").local(__.select("a","b").by("name")) }], 
+    g_VX1X_asXaX_repeatXout_asXaXX_timesX2X_selectXlast_aX: [function({g, vid1}) { return g.V(vid1).as("a").repeat(__.out().as("a")).times(2).select(Pop.last,"a") }], 
+    g_VX1X_outEXknowsX_asXhereX_hasXweight_1X_inV_hasXname_joshX_selectXhereX: [function({g, vid1}) { return g.V(vid1).outE("knows").as("here").has("weight",1.0).inV().has("name","josh").select("here") }], 
+    g_V_asXaX_hasXname_markoX_asXbX_asXcX_selectXa_b_cX_by_byXnameX_byXageX: [function({g}) { return g.V().as("a").has("name","marko").as("b").as("c").select("a","b","c").by().by("name").by("age") }], 
+    g_V_outE_weight_groupCount_selectXvaluesX_unfold_groupCount_selectXvaluesX_unfold: [function({g}) { return g.V().outE().values("weight").groupCount().select(Column.values).unfold().groupCount().select(Column.values).unfold() }], 
+    g_V_asXaX_groupXmX_by_byXbothE_countX_barrier_selectXmX_selectXselectXaXX: [function({g}) { return g.V().as("a").group("m").by().by(__.bothE().count()).barrier().select("m").select(__.select("a")) }], 
+    g_V_asXaX_groupXmX_by_byXbothE_countX_barrier_selectXmX_selectXselectXaXX_byXmathX_plus_XX: [function({g}) { return g.V().as("a").group("m").by().by(__.bothE().count()).barrier().select("m").select(__.select("a")).by(__.math("_+_")) }], 
+    g_V_asXaX_outXknowsX_asXaX_selectXall_constantXaXX: [function({g}) { return g.V().as("a").out("knows").as("a").select(Pop.all,__.constant("a")) }], 
+    g_V_selectXaX: [function({g}) { return g.V().select("a") }], 
+    g_V_selectXaX_count: [function({g}) { return g.V().select("a").count() }], 
+    g_V_selectXa_bX: [function({g}) { return g.V().select("a","b") }], 
+    g_V_valueMap_selectXaX: [function({g}) { return g.V().valueMap().select("a") }], 
+    g_V_valueMap_selectXa_bX: [function({g}) { return g.V().valueMap().select("a","b") }], 
+    g_V_selectXfirst_aX: [function({g}) { return g.V().select(Pop.first,"a") }], 
+    g_V_selectXfirst_a_bX: [function({g}) { return g.V().select(Pop.first,"a","b") }], 
+    g_V_valueMap_selectXfirst_aX: [function({g}) { return g.V().valueMap().select(Pop.first,"a") }], 
+    g_V_valueMap_selectXfirst_a_bX: [function({g}) { return g.V().valueMap().select(Pop.first,"a","b") }], 
+    g_V_selectXlast_aX: [function({g}) { return g.V().select(Pop.last,"a") }], 
+    g_V_selectXlast_a_bX: [function({g}) { return g.V().select(Pop.last,"a","b") }], 
+    g_V_valueMap_selectXlast_aX: [function({g}) { return g.V().valueMap().select(Pop.last,"a") }], 
+    g_V_valueMap_selectXlast_a_bX: [function({g}) { return g.V().valueMap().select(Pop.last,"a","b") }], 
+    g_V_selectXall_aX: [function({g}) { return g.V().select(Pop.all,"a") }], 
+    g_V_selectXall_a_bX: [function({g}) { return g.V().select(Pop.all,"a","b") }], 
+    g_V_valueMap_selectXall_aX: [function({g}) { return g.V().valueMap().select(Pop.all,"a") }], 
+    g_V_valueMap_selectXall_a_bX: [function({g}) { return g.V().valueMap().select(Pop.all,"a","b") }], 
+    g_V_asXa_bX_out_asXcX_path_selectXkeysX: [function({g}) { return g.V().as("a","b").out().as("c").path().select(Column.keys) }, function({g}) { return g.V().as("a","b").out().as("c").path().select(Column.keys) }], 
+    g_V_hasXperson_name_markoX_barrier_asXaX_outXknows_selectXaX: [function({g}) { return g.V().has("person","name","marko").barrier().as("a").out("knows").select("a") }], 
+    g_V_hasXperson_name_markoX_elementMapXnameX_asXaX_unionXidentity_identityX_selectXaX_selectXnameX: [function({g}) { return g.V().has("person","name","marko").elementMap("name").as("a").union(__.identity(),__.identity()).select("a").select("name") }], 
+    g_V_hasXperson_name_markoX_count_asXaX_unionXidentity_identityX_selectXaX: [function({g}) { return g.V().has("person","name","marko").count().as("a").union(__.identity(),__.identity()).select("a") }], 
+    g_V_hasXperson_name_markoX_path_asXaX_unionXidentity_identityX_selectXaX_unfold: [function({g}) { return g.V().has("person","name","marko").path().as("a").union(__.identity(),__.identity()).select("a").unfold() }], 
+    g_EX11X_propertiesXweightX_asXaX_selectXaX_byXkeyX: [function({g, eid11}) { return g.E(eid11).properties("weight").as("a").select("a").by(T.key) }], 
+    g_EX11X_propertiesXweightX_asXaX_selectXaX_byXvalueX: [function({g, eid11}) { return g.E(eid11).properties("weight").as("a").select("a").by(T.value) }], 
+    g_V_shortestPath: [function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().identity().shortestPath() }], 
+    g_V_both_dedup_shortestPath: [function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().both().dedup().shortestPath() }], 
+    g_V_shortestPath_edgesIncluded: [function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().identity().shortestPath().with_("~tinkerpop.shortestPath.includeEdges") }], 
+    g_V_shortestPath_directionXINX: [function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().identity().shortestPath().with_("~tinkerpop.shortestPath.edges",Direction.IN) }], 
+    g_V_shortestPath_edgesXoutEX: [function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().identity().shortestPath().with_("~tinkerpop.shortestPath.edges",__.outE()) }], 
+    g_V_shortestPath_edgesIncluded_edgesXoutEX: [function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().identity().shortestPath().with_("~tinkerpop.shortestPath.includeEdges").with_("~tinkerpop.shortestPath.edges",__.outE()) }], 
+    g_V_hasXname_markoX_shortestPath: [function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().has("name","marko").shortestPath() }], 
+    g_V_shortestPath_targetXhasXname_markoXX: [function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().identity().shortestPath().with_("~tinkerpop.shortestPath.target",__.has("name","marko")) }], 
+    g_V_shortestPath_targetXvaluesXnameX_isXmarkoXX: [function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().identity().shortestPath().with_("~tinkerpop.shortestPath.target",__.values("name").is("marko")) }], 
+    g_V_hasXname_markoX_shortestPath_targetXhasLabelXsoftwareXX: [function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().has("name","marko").shortestPath().with_("~tinkerpop.shortestPath.target",__.hasLabel("software")) }], 
+    g_V_hasXname_markoX_shortestPath_targetXhasXname_joshXX_distanceXweightX: [function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().has("name","marko").shortestPath().with_("~tinkerpop.shortestPath.target",__.has("name","josh")).with_("~tinkerpop.shortestPath.distance","weight") }], 
+    g_V_hasXname_danielX_shortestPath_targetXhasXname_stephenXX_edgesXbothEXusesXX: [function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().has("name","daniel").shortestPath().with_("~tinkerpop.shortestPath.target",__.has("name","stephen")).with_("~tinkerpop.shortestPath.edges",__.bothE("uses")) }], 
+    g_V_hasXsong_name_MIGHT_AS_WELLX_shortestPath_targetXhasXsong_name_MAYBE_YOU_KNOW_HOW_I_FEELXX_edgesXoutEXfollowedByXX_distanceXweightX: [function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().has("song","name","MIGHT AS WELL").shortestPath().with_("~tinkerpop.shortestPath.target",__.has("song","name","MAYBE YOU KNOW HOW I FEEL")).with_("~tinkerpop.shortestPath.edges",__.outE("followedBy")).with_("~tinkerpop.shortestPath.distance","weight") }], 
+    g_V_hasXname_markoX_shortestPath_maxDistanceX1X: [function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().has("name","marko").shortestPath().with_("~tinkerpop.shortestPath.maxDistance",1) }], 
+    g_V_hasXname_vadasX_shortestPath_distanceXweightX_maxDistanceX1_3X: [function({g}) { return g.withStrategies(new VertexProgramStrategy(new Map([["graphComputer","org.apache.tinkerpop.gremlin.process.computer.GraphComputer"]]))).V().has("name","vadas").shortestPath().with_("~tinkerpop.shortestPath.distance","weight").with_("~tinkerpop.shortestPath.maxDistance",1.3) }], 
+    g_V_age_sum: [function({g}) { return g.V().values("age").sum() }], 
+    g_V_foo_sum: [function({g}) { return g.V().values("foo").sum() }], 
+    g_V_age_fold_sumXlocalX: [function({g}) { return g.V().values("age").fold().sum(Scope.local) }], 
+    g_V_foo_fold_sumXlocalX: [function({g}) { return g.V().values("foo").fold().sum(Scope.local) }], 
+    g_V_hasLabelXsoftwareX_group_byXnameX_byXbothE_weight_sumX: [function({g}) { return g.V().hasLabel("software").group().by("name").by(__.bothE().values("weight").sum()) }], 
+    g_V_localXoutE_foldX_unfold: [function({g}) { return g.V().local(__.outE().fold()).unfold() }], 
+    g_V_valueMap_unfold_mapXkeyX: [function({g, l1}) { return g.V().valueMap().unfold().map(l1) }], 
+    g_VX1X_repeatXboth_simplePathX_untilXhasIdX6XX_path_byXnameX_unfold: [function({g, vid6, vid1}) { return g.V(vid1).repeat(__.both().simplePath()).until(__.hasId(vid6)).path().by("name").unfold() }], 
+    g_V_valueMap: [function({g}) { return g.V().valueMap() }], 
+    g_V_valueMapXtrueX: [function({g}) { return g.V().valueMap(true) }], 
+    g_V_valueMap_withXtokensX: [function({g}) { return g.V().valueMap().with_("~tinkerpop.valueMap.tokens") }], 
+    g_V_valueMapXname_ageX: [function({g}) { return g.V().valueMap("name","age") }], 
+    g_V_valueMapXtrue_name_ageX: [function({g}) { return g.V().valueMap(true,"name","age") }], 
+    g_V_valueMapXname_ageX_withXtokensX: [function({g}) { return g.V().valueMap("name","age").with_("~tinkerpop.valueMap.tokens") }], 
+    g_V_valueMapXname_ageX_withXtokens_labelsX_byXunfoldX: [function({g}) { return g.V().valueMap("name","age").with_("~tinkerpop.valueMap.tokens",2).by(__.unfold()) }], 
+    g_V_valueMapXname_ageX_withXtokens_idsX_byXunfoldX: [function({g}) { return g.V().valueMap("name","age").with_("~tinkerpop.valueMap.tokens",1).by(__.unfold()) }], 
+    g_VX1X_outXcreatedX_valueMap: [function({g, vid1}) { return g.V(vid1).out("created").valueMap() }], 
+    g_V_hasLabelXpersonX_filterXoutEXcreatedXX_valueMapXtrueX: [function({g}) { return g.V().hasLabel("person").filter(__.outE("created")).valueMap(true) }], 
+    g_V_hasLabelXpersonX_filterXoutEXcreatedXX_valueMap_withXtokensX: [function({g}) { return g.V().hasLabel("person").filter(__.outE("created")).valueMap().with_("~tinkerpop.valueMap.tokens") }], 
+    g_VX1X_valueMapXname_locationX_byXunfoldX_by: [function({g, vid1}) { return g.V(vid1).valueMap("name","location").by(__.unfold()).by() }], 
+    g_VXlistX1_2_3XX_name: [function({g, xx1}) { return g.V(xx1).values("name") }], 
+    g_VXlistXv1_v2_v3XX_name: [function({g, xx1}) { return g.V(xx1).values("name") }], 
+    g_V: [function({g}) { return g.V() }], 
+    g_VXv1X_out: [function({g, v1}) { return g.V(v1).out() }], 
+    g_VX1X_out: [function({g, vid1}) { return g.V(vid1).out() }], 
+    g_VX2X_in: [function({g, vid2}) { return g.V(vid2).in_() }], 
+    g_VX4X_both: [function({g, vid4}) { return g.V(vid4).both() }], 
+    g_E: [function({g}) { return g.E() }], 
+    g_EX11X: [function({g, eid11}) { return g.E(eid11) }], 
+    g_EX11AsStringX: [function({g, eid11}) { return g.E(eid11) }], 
+    g_EXe11X: [function({g, e11}) { return g.E(e11) }], 
+    g_EXe7_e11X: [function({g, e7, e11}) { return g.E(e7,e11) }], 
+    g_EXlistXe7_e11XX: [function({g, xx1}) { return g.E(xx1) }], 
+    g_VX1X_outE: [function({g, vid1}) { return g.V(vid1).outE() }], 
+    g_VX2X_outE: [function({g, vid2}) { return g.V(vid2).inE() }], 
+    g_VX4X_bothEXcreatedX: [function({g, vid4}) { return g.V(vid4).bothE("created") }], 
+    g_VX4X_bothE: [function({g, vid4}) { return g.V(vid4).bothE() }], 
+    g_VX1X_outE_inV: [function({g, vid1}) { return g.V(vid1).both() }], 
+    g_VX2X_inE_outV: [function({g, vid2}) { return g.V(vid2).inE().outV() }], 
+    g_V_outE_hasXweight_1X_outV: [function({g}) { return g.V().outE().has("weight",1.0).outV() }], 
+    g_V_out_outE_inV_inE_inV_both_name: [function({g}) { return g.V().out().outE().inV().inE().inV().both().values("name") }], 
+    g_VX1X_outEXknowsX_bothV_name: [function({g, vid1}) { return g.V(vid1).outE("knows").bothV().values("name") }], 
+    g_VX1X_outE_otherV: [function({g, vid1}) { return g.V(vid1).outE().otherV() }], 
+    g_VX4X_bothE_otherV: [function({g, vid4}) { return g.V(vid4).bothE().otherV() }], 
+    g_VX4X_bothE_hasXweight_lt_1X_otherV: [function({g, vid4}) { return g.V(vid4).bothE().has("weight",P.lt(1.0)).otherV() }], 
+    g_VX2X_inE: [function({g, vid2}) { return g.V(vid2).bothE() }], 
+    get_g_VX1X_outE_otherV: [function({g, vid1}) { return g.V(vid1).outE().otherV() }], 
+    g_VX1X_outXknowsX: [function({g, vid1}) { return g.V(vid1).out("knows") }], 
+    g_VX1AsStringX_outXknowsX: [function({g, vid1}) { return g.V(vid1).out("knows") }], 
+    g_VX1X_outXknows_createdX: [function({g, vid1}) { return g.V(vid1).out("knows","created") }], 
+    g_VX1X_outEXknowsX_inV: [function({g, vid1}) { return g.V(vid1).outE("knows").inV() }], 
+    g_VX1X_outEXknows_createdX_inV: [function({g, vid1}) { return g.V(vid1).outE("knows","created").inV() }], 
+    g_V_out_out: [function({g}) { return g.V().out().out() }], 
+    g_VX1X_out_out_out: [function({g, vid1}) { return g.V(vid1).out().out().out() }], 
+    g_VX1X_out_name: [function({g, vid1}) { return g.V(vid1).out().values("name") }], 
+    g_VX1X_to_XOUT_knowsX: [function({g, vid1}) { return g.V(vid1).to(Direction.OUT,"knows") }], 
+    g_VX1_2_3_4X_name: [function({g, vid4, vid3, vid2, vid1}) { return g.V(vid1,vid2,vid3,vid4).values("name") }], 
+    g_V_hasLabelXpersonX_V_hasLabelXsoftwareX_name: [function({g}) { return g.V().hasLabel("person").V().hasLabel("software").values("name") }], 
+    g_V_hasLabelXloopsX_bothEXselfX: [function({g}) { return g.V().hasLabel("loops").bothE("self") }], 
+    g_V_hasLabelXloopsX_bothXselfX: [function({g}) { return g.V().hasLabel("loops").both("self") }], 
+    g_V_valueXnameX_aggregateXxX_capXxX: [function({g}) { return g.V().values("name").aggregate("x").cap("x") }], 
+    g_V_valueXnameX_aggregateXglobal_xX_capXxX: [function({g}) { return g.V().values("name").aggregate(Scope.global,"x").cap("x") }], 
+    g_V_aggregateXxX_byXnameX_capXxX: [function({g}) { return g.V().aggregate("x").by("name").cap("x") }], 
+    g_V_out_aggregateXaX_path: [function({g}) { return g.V().out().aggregate("a").path() }], 
+    g_V_hasLabelXpersonX_aggregateXxX_byXageX_capXxX_asXyX_selectXyX: [function({g}) { return g.V().hasLabel("person").aggregate("x").by("age").cap("x").as("y").select("y") }], 
+    g_V_aggregateXlocal_a_nameX_out_capXaX: [function({g}) { return g.V().aggregate(Scope.local,"a").by("name").out().cap("a") }], 
+    g_VX1X_aggregateXlocal_aX_byXnameX_out_aggregateXlocal_aX_byXnameX_name_capXaX: [function({g, vid1}) { return g.V(vid1).aggregate(Scope.local,"a").by("name").out().aggregate(Scope.local,"a").by("name").values("name").cap("a") }], 
+    g_withSideEffectXa_setX_V_both_name_aggregateXlocal_aX_capXaX: [function({g, xx1}) { return g.withSideEffect("a",xx1).V().both().values("name").aggregate(Scope.local,"a").cap("a") }], 
+    g_V_aggregateXlocal_aX_byXoutEXcreatedX_countX_out_out_aggregateXlocal_aX_byXinEXcreatedX_weight_sumX: [function({g}) { return g.V().aggregate(Scope.local,"a").by(__.outE("created").count()).out().out().aggregate(Scope.local,"a").by(__.inE("created").values("weight").sum()).cap("a") }], 
+    g_V_group_byXnameX: [function({g}) { return g.V().group().by("name") }], 
+    g_V_group_byXageX: [function({g}) { return g.V().group().by("age") }], 
+    g_V_group_byXnameX_by: [function({g}) { return g.V().group().by("name").by() }], 
+    g_V_groupXaX_byXnameX_capXaX: [function({g}) { return g.V().group("a").by("name").cap("a") }], 
+    g_V_hasXlangX_groupXaX_byXlangX_byXnameX_out_capXaX: [function({g}) { return g.V().has("lang").group("a").by("lang").by("name").out().cap("a") }], 
+    g_V_hasXlangX_group_byXlangX_byXcountX: [function({g}) { return g.V().has("lang").group().by("lang").by(__.count()) }], 
+    g_V_repeatXout_groupXaX_byXnameX_byXcountX_timesX2X_capXaX: [function({g}) { return g.V().repeat(__.out().group("a").by("name").by(__.count())).times(2).cap("a") }], 
+    g_V_group_byXoutE_countX_byXnameX: [function({g}) { return g.V().group().by(__.outE().count()).by("name") }], 
+    g_V_groupXaX_byXlabelX_byXoutE_weight_sumX_capXaX: [function({g}) { return g.V().group("a").by(T.label).by(__.outE().values("weight").sum()).cap("a") }], 
+    g_V_repeatXbothXfollowedByXX_timesX2X_group_byXsongTypeX_byXcountX: [function({g}) { return g.V().repeat(__.both("followedBy")).times(2).group().by("songType").by(__.count()) }], 
+    g_V_repeatXbothXfollowedByXX_timesX2X_groupXaX_byXsongTypeX_byXcountX_capXaX: [function({g}) { return g.V().repeat(__.both("followedBy")).times(2).group("a").by("songType").by(__.count()).cap("a") }], 
+    g_V_group_byXname_substring_1X_byXconstantX1XX: [function({g, l1}) { return g.V().group().by(l1).by(__.constant(1)) }], 
+    g_V_groupXaX_byXname_substring_1X_byXconstantX1XX_capXaX: [function({g, l1}) { return g.V().group("a").by(l1).by(__.constant(1)).cap("a") }], 
+    g_V_out_group_byXlabelX_selectXpersonX_unfold_outXcreatedX_name_limitX2X: [function({g}) { return g.V().out().group().by(T.label).select("person").unfold().out("created").values("name").limit(2) }], 
+    g_V_hasLabelXsongX_group_byXnameX_byXproperties_groupCount_byXlabelXX: [function({g}) { return g.V().hasLabel("song").group().by("name").by(__.properties().groupCount().by(T.label)) }], 
+    g_V_hasLabelXsongX_groupXaX_byXnameX_byXproperties_groupCount_byXlabelXX_out_capXaX: [function({g}) { return g.V().hasLabel("song").group("a").by("name").by(__.properties().groupCount().by(T.label)).out().cap("a") }], 
+    g_V_outXfollowedByX_group_byXsongTypeX_byXbothE_group_byXlabelX_byXweight_sumXX: [function({g}) { return g.V().out("followedBy").group().by("songType").by(__.bothE().group().by(T.label).by(__.values("weight").sum())) }], 
+    g_V_groupXmX_byXnameX_byXinXknowsX_nameX_capXmX: [function({g}) { return g.V().group("m").by("name").by(__.in_("knows").values("name")).cap("m") }], 
+    g_V_group_byXlabelX_byXbothE_groupXaX_byXlabelX_byXweight_sumX_weight_sumX: [function({g}) { return g.V().group().by(T.label).by(__.bothE().group("a").by(T.label).by(__.values("weight").sum()).values("weight").sum()) }], 
+    g_withSideEffectXa__marko_666_noone_blahX_V_groupXaX_byXnameX_byXoutE_label_foldX_capXaX: [function({g, xx1}) { return g.withSideEffect("a",xx1).V().group("a").by("name").by(__.outE().label().fold()).cap("a") }], 
+    g_V_hasLabelXpersonX_asXpX_outXcreatedX_group_byXnameX_byXselectXpX_valuesXageX_sumX: [function({g}) { return g.V().hasLabel("person").as("p").out("created").group().by("name").by(__.select("p").values("age").sum()) }], 
+    g_V_hasLabelXpersonX_asXpX_outXcreatedX_groupXaX_byXnameX_byXselectXpX_valuesXageX_sumX_capXaX: [function({g}) { return g.V().hasLabel("person").as("p").out("created").group("a").by("name").by(__.select("p").values("age").sum()).cap("a") }], 
+    g_V_group_byXlabelX_byXlabel_countX: [function({g}) { return g.V().group().by(__.label()).by(__.label().count()) }], 
+    g_V_groupXmX_byXlabelX_byXlabel_countX_capXmX: [function({g}) { return g.V().group("m").by(__.label()).by(__.label().count()).cap("m") }], 
+    g_V_outXcreatedX_groupCount_byXnameX: [function({g}) { return g.V().out("created").groupCount().by("name") }], 
+    g_V_outXcreatedX_name_groupCount: [function({g}) { return g.V().out("created").values("name").groupCount() }], 
+    g_V_outXcreatedX_groupCountXaX_byXnameX_capXaX: [function({g}) { return g.V().out("created").groupCount("a").by("name").cap("a") }], 
+    g_V_outXcreatedX_name_groupCountXaX_capXaX: [function({g}) { return g.V().out("created").values("name").groupCount("a").cap("a") }], 
+    g_V_repeatXout_groupCountXaX_byXnameXX_timesX2X_capXaX: [function({g}) { return g.V().repeat(__.out().groupCount("a").by("name")).times(2).cap("a") }], 
+    g_V_both_groupCountXaX_byXlabelX_asXbX_barrier_whereXselectXaX_selectXsoftwareX_isXgtX2XXX_selectXbX_name: [function({g}) { return g.V().both().groupCount("a").by(T.label).as("b").barrier().where(__.select("a").select("software").is(P.gt(2))).select("b").values("name") }], 
+    g_V_unionXoutXknowsX__outXcreatedX_inXcreatedXX_groupCount_selectXvaluesX_unfold_sum: [function({g}) { return g.V().union(__.out("knows"),__.out("created").in_("created")).groupCount().select(Column.values).unfold().sum() }], 
+    g_V_hasXnoX_groupCount: [function({g}) { return g.V().has("no").groupCount() }], 
+    g_V_hasXnoX_groupCountXaX_capXaX: [function({g}) { return g.V().has("no").groupCount("a").cap("a") }], 
+    g_V_unionXrepeatXoutX_timesX2X_groupCountXmX_byXlangXX__repeatXinX_timesX2X_groupCountXmX_byXnameXX_capXmX: [function({g}) { return g.V().union(__.repeat(__.out()).times(2).groupCount("m").by("lang"),__.repeat(__.in_()).times(2).groupCount("m").by("name")).cap("m") }], 
+    g_V_outXcreatedX_groupCountXxX_capXxX: [function({g}) { return g.V().out("created").groupCount("x").cap("x") }], 
+    g_V_groupCount_byXbothE_countX: [function({g}) { return g.V().groupCount().by(__.bothE().count()) }], 
+    g_V_both_groupCountXaX_out_capXaX_selectXkeysX_unfold_both_groupCountXaX_capXaX: [function({g}) { return g.V().both().groupCount("a").out().cap("a").select(Column.keys).unfold().both().groupCount("a").cap("a") }], 
+    g_V_hasXperson_name_markoX_bothXknowsX_groupCount_byXvaluesXnameX_foldX: [function({g}) { return g.V().has("person","name","marko").both("knows").groupCount().by(__.values("name").fold()) }], 
+    g_VX1X_out_injectXv2X_name: [function({g, vid1, v2}) { return g.V(vid1).out().inject(v2).values("name") }], 
+    g_VX1X_out_name_injectXdanielX_asXaX_mapXlengthX_path: [function({g, l1, vid1}) { return g.V(vid1).out().values("name").inject("daniel").as("a").map(l1).path() }], 
+    g_VX1X_injectXg_VX4XX_out_name: [function({g, vid1, v4}) { return g.V(vid1).inject(v4).out().values("name") }], 
+    g_injectXnull_1_3_nullX: [function({g}) { return g.inject(null,1,3,null) }], 
+    g_injectX10_20_null_20_10_10X_groupCountXxX_dedup_asXyX_projectXa_bX_by_byXselectXxX_selectXselectXyXXX: [function({g}) { return g.inject(10,20,null,20,10,10).groupCount("x").dedup().as("y").project("a","b").by().by(__.select("x").select(__.select("y"))) }], 
+    g_injectXname_marko_age_nullX_selectXname_ageX: [function({g, xx1}) { return g.inject(xx1).select("name","age") }], 
+    g_io_readXkryoX: [function({g}) { return g.io("data/tinkerpop-modern.kryo").read() }, function({g}) { return g.V() }, function({g}) { return g.E() }], 
+    g_io_read_withXreader_gryoX: [function({g}) { return g.io("data/tinkerpop-modern.kryo").with_("~tinkerpop.io.reader","gryo").read() }, function({g}) { return g.V() }, function({g}) { return g.E() }], 
+    g_io_readXgraphsonX: [function({g}) { return g.io("data/tinkerpop-modern.json").read() }, function({g}) { return g.V() }, function({g}) { return g.E() }], 
+    g_io_read_withXreader_graphsonX: [function({g}) { return g.io("data/tinkerpop-modern.json").with_("~tinkerpop.io.reader","graphson").read() }, function({g}) { return g.V() }, function({g}) { return g.E() }], 
+    g_io_readXgraphmlX: [function({g}) { return g.io("data/tinkerpop-modern.xml").read() }, function({g}) { return g.V() }, function({g}) { return g.E() }], 
+    g_io_read_withXreader_graphmlX: [function({g}) { return g.io("data/tinkerpop-modern.xml").with_("~tinkerpop.io.reader","graphml").read() }, function({g}) { return g.V() }, function({g}) { return g.E() }], 
+    g_withSackXhelloX_V_outE_sackXassignX_byXlabelX_inV_sack: [function({g}) { return g.withSack("hello").V().outE().sack(Operator.assign).by(T.label).inV().sack() }], 
+    g_withSackX0X_V_outE_sackXsumX_byXweightX_inV_sack_sum: [function({g}) { return g.withSack(0.0).V().outE().sack(Operator.sum).by("weight").inV().sack().sum() }], 
+    g_withSackX0X_V_repeatXoutE_sackXsumX_byXweightX_inVX_timesX2X_sack: [function({g}) { return g.withSack(0.0).V().repeat(__.outE().sack(Operator.sum).by("weight").inV()).times(2).sack() }], 
+    g_withBulkXfalseX_withSackX1_sumX_VX1X_localXoutEXknowsX_barrierXnormSackX_inVX_inXknowsX_barrier_sack: [function({g, vid1}) { return g.withBulk(false).withSack(1.0,Operator.sum).V(vid1).local(__.outE("knows").barrier(Barrier.normSack).inV()).in_("knows").barrier().sack() }], 
+    g_withBulkXfalseX_withSackX1_sumX_V_out_barrier_sack: [function({g}) { return g.withBulk(false).withSack(1,Operator.sum).V().out().barrier().sack() }], 
+    g_withSackX1_sumX_VX1X_localXoutXknowsX_barrierXnormSackXX_inXknowsX_barrier_sack: [function({g, vid1}) { return g.withSack(1.0,Operator.sum).V(vid1).local(__.out("knows").barrier(Barrier.normSack)).in_("knows").barrier().sack() }], 
+    g_V_hasXageX_groupCountXaX_byXnameX_out_capXaX: [function({g}) { return g.V().has("age").groupCount("a").by("name").out().cap("a") }], 
+    g_V_storeXa_nameX_out_capXaX: [function({g}) { return g.V().store("a").by("name").out().cap("a") }], 
+    g_VX1X_storeXaX_byXnameX_out_storeXaX_byXnameX_name_capXaX: [function({g, vid1}) { return g.V(vid1).store("a").by("name").out().store("a").by("name").values("name").cap("a") }], 
+    g_withSideEffectXa_setX_V_both_name_storeXaX_capXaX: [function({g, xx1}) { return g.withSideEffect("a",xx1).V().both().values("name").store("a").cap("a") }], 
+    g_V_storeXaX_byXoutEXcreatedX_countX_out_out_storeXaX_byXinEXcreatedX_weight_sumX: [function({g}) { return g.V().store("a").by(__.outE("created").count()).out().out().store("a").by(__.inE("created").values("weight").sum()).cap("a") }], 
+}
+
+exports.gremlin = gremlins
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/client-test.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/client-test.js
index e135047..426f851 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/client-test.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/client-test.js
@@ -55,4 +55,20 @@
     customClient._connection = connectionMock;
     customClient.submit(query)
   });
+
+  it('should allow to submit extra arguments', function () {
+    const connectionMock = {
+      submit: function (processor, op, args, requestId) {
+        assert.strictEqual(args.gremlin, query);
+        assert.strictEqual(args.evaluationTimeout, 123);
+        assert.strictEqual(processor, customOpProcessor);
+
+        return Promise.resolve();
+      }
+    };
+
+    const customClient = new Client('ws://localhost:9321', {traversalSource: 'g', processor: customOpProcessor});
+    customClient._connection = connectionMock;
+    customClient.submit(query, null, {"evaluationTimeout": 123})
+  });
 });
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphson-test.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphson-test.js
index d855cb0..cc7febc 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphson-test.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphson-test.js
@@ -32,6 +32,11 @@
 const P = t.P;
 
 describe('GraphSONReader', function () {
+  it('should parse GraphSON null', function () {
+    const reader = new GraphSONReader();
+    const result = reader.read(null);
+    assert.equal(result, null);
+  });
   it('should parse GraphSON int32, float and double to Number from GraphSON', function () {
     const reader = new GraphSONReader();
     [
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/translator-test.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/translator-test.js
index 033c816..0438915 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/translator-test.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/translator-test.js
@@ -52,9 +52,9 @@
 
     it('should produce valid script representation from bytecode glv steps containing enum', function () {
       const g = new graph.Graph().traversal();
-      const script = new Translator('g').translate(g.V().order().by('age', t.order.decr).getBytecode());
+      const script = new Translator('g').translate(g.V().order().by('age', t.order.shuffle).getBytecode());
       assert.ok(script);
-      assert.strictEqual(script, 'g.V().order().by(\'age\', decr)');
+      assert.strictEqual(script, 'g.V().order().by(\'age\', shuffle)');
     });
 
     it('should produce valid script representation from bytecode glv steps containing a predicate', function () {
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/traversal-test.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/traversal-test.js
index b56f824..273f2c4 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/traversal-test.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/traversal-test.js
@@ -25,7 +25,10 @@
 const assert = require('assert');
 const expect = require('chai').expect;
 const graph = require('../../lib/structure/graph');
+const anon = require('../../lib/process/anonymous-traversal');
 const t = require('../../lib/process/traversal');
+const gt = require('../../lib/process/graph-traversal');
+const V = gt.statics.V;
 const P = t.P;
 const Bytecode = require('../../lib/process/bytecode');
 const TraversalStrategies = require('../../lib/process/traversal-strategy').TraversalStrategies;
@@ -34,7 +37,7 @@
 
   describe('#getByteCode()', function () {
     it('should add steps for with a string parameter', function () {
-      const g = new graph.Graph().traversal();
+      const g = anon.traversal().withGraph(new graph.Graph());
       const bytecode = g.V().out('created').getBytecode();
       assert.ok(bytecode);
       assert.strictEqual(bytecode.sourceInstructions.length, 0);
@@ -45,7 +48,7 @@
     });
 
     it('should add steps with an enum value', function () {
-      const g = new graph.Graph().traversal();
+      const g = anon.traversal().withGraph(new graph.Graph());
       const bytecode = g.V().order().by('age', t.order.desc).getBytecode();
       assert.ok(bytecode);
       assert.strictEqual(bytecode.sourceInstructions.length, 0);
@@ -229,4 +232,17 @@
       assert.strictEqual(P.within(['a', 'b']).toString(), 'within(\'a\',\'b\')');
     });
   });
+
+  describe("build", function() {
+    it('should only allow anonymous child traversals', function() {
+      const g = anon.traversal().withGraph(new graph.Graph());
+      assert.doesNotThrow(function() {
+        g.V(0).addE("self").to(V(1))
+      });
+
+      assert.throws(function() {
+        g.V(0).addE("self").to(g.V(1))
+      });
+    })
+  });
 });
\ No newline at end of file
diff --git a/gremlin-language/pom.xml b/gremlin-language/pom.xml
new file mode 100644
index 0000000..2cc88f4
--- /dev/null
+++ b/gremlin-language/pom.xml
@@ -0,0 +1,89 @@
+<!--
+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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.tinkerpop</groupId>
+        <artifactId>tinkerpop</artifactId>
+        <version>3.5.1-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>gremlin-language</artifactId>
+    <name>Apache TinkerPop :: Gremlin Language</name>
+    <dependencies>
+        <dependency>
+            <groupId>org.antlr</groupId>
+            <artifactId>antlr4</artifactId>
+            <version>${antlr4.version}</version>
+        </dependency>
+        <!-- TESTING -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.hamcrest</groupId>
+            <artifactId>hamcrest</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-text</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <properties>
+        <antlr4.version>4.9.1</antlr4.version>
+    </properties>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.antlr</groupId>
+                <artifactId>antlr4-maven-plugin</artifactId>
+                <version>${antlr4.version}</version>
+                <executions>
+                    <execution>
+                        <id>antlr</id>
+                        <goals>
+                            <goal>antlr4</goal>
+                        </goals>
+                        <configuration>
+                            <arguments>
+                                <argument>-package</argument>
+                                <argument>org.apache.tinkerpop.gremlin.language.grammar</argument>
+                                <argument>-encoding</argument>
+                                <argument>utf-8</argument>
+                            </arguments>
+                            <visitor>true</visitor>
+                            <outputDirectory>${project.build.directory}/generated-sources/antlr4/org/apache/tinkerpop/gremlin/language/grammar/</outputDirectory>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
\ No newline at end of file
diff --git a/gremlin-language/src/main/antlr4/Gremlin.g4 b/gremlin-language/src/main/antlr4/Gremlin.g4
new file mode 100644
index 0000000..2ea796f
--- /dev/null
+++ b/gremlin-language/src/main/antlr4/Gremlin.g4
@@ -0,0 +1,1547 @@
+/*
+ * 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.
+ */
+grammar Gremlin;
+
+/*********************************************
+    PARSER RULES
+**********************************************/
+
+queryList
+    : query (SEMI? query)* SEMI? EOF
+    ;
+
+query
+    : traversalSource
+    | traversalSource DOT transactionPart
+    | rootTraversal
+    | rootTraversal DOT traversalTerminalMethod
+    | query DOT 'toString' LPAREN RPAREN
+    | emptyQuery
+    ;
+
+emptyQuery
+    : EmptyStringLiteral
+    ;
+
+traversalSource
+    : TRAVERSAL_ROOT
+    | TRAVERSAL_ROOT DOT traversalSourceSelfMethod
+    | traversalSource DOT traversalSourceSelfMethod
+    ;
+
+transactionPart
+    : 'tx' LPAREN RPAREN DOT 'commit' LPAREN RPAREN
+    | 'tx' LPAREN RPAREN DOT 'rollback' LPAREN RPAREN
+    | 'tx' LPAREN RPAREN
+    ;
+
+rootTraversal
+    : traversalSource DOT traversalSourceSpawnMethod
+    | traversalSource DOT traversalSourceSpawnMethod DOT chainedTraversal
+    | traversalSource DOT traversalSourceSpawnMethod DOT chainedParentOfGraphTraversal
+    ;
+
+traversalSourceSelfMethod
+    : traversalSourceSelfMethod_withBulk
+    | traversalSourceSelfMethod_withPath
+    | traversalSourceSelfMethod_withSack
+    | traversalSourceSelfMethod_withSideEffect
+    | traversalSourceSelfMethod_withStrategies
+    | traversalSourceSelfMethod_with
+    ;
+
+traversalSourceSelfMethod_withBulk
+    : 'withBulk' LPAREN booleanLiteral RPAREN
+    ;
+
+traversalSourceSelfMethod_withPath
+    : 'withPath' LPAREN RPAREN
+    ;
+
+traversalSourceSelfMethod_withSack
+    : 'withSack' LPAREN genericLiteral RPAREN
+    | 'withSack' LPAREN genericLiteral COMMA traversalOperator RPAREN
+    ;
+
+traversalSourceSelfMethod_withSideEffect
+    : 'withSideEffect' LPAREN stringLiteral COMMA genericLiteral RPAREN
+    ;
+
+traversalSourceSelfMethod_withStrategies
+    : 'withStrategies' LPAREN traversalStrategy (COMMA traversalStrategyList)? RPAREN
+    ;
+
+traversalSourceSelfMethod_with
+    : 'with' LPAREN stringLiteral RPAREN
+    | 'with' LPAREN stringLiteral COMMA genericLiteral RPAREN
+    ;
+
+traversalSourceSpawnMethod
+	: traversalSourceSpawnMethod_addE
+	| traversalSourceSpawnMethod_addV
+	| traversalSourceSpawnMethod_E
+	| traversalSourceSpawnMethod_V
+	| traversalSourceSpawnMethod_inject
+    | traversalSourceSpawnMethod_io
+    ;
+
+traversalSourceSpawnMethod_addE
+	: 'addE' LPAREN stringLiteral RPAREN
+	| 'addE' LPAREN nestedTraversal RPAREN
+	;
+
+traversalSourceSpawnMethod_addV
+	: 'addV' LPAREN RPAREN
+	| 'addV' LPAREN stringLiteral RPAREN
+	| 'addV' LPAREN nullLiteral RPAREN          // null means use the default vertex label
+	| 'addV' LPAREN nestedTraversal RPAREN
+	;
+
+traversalSourceSpawnMethod_E
+	: 'E' LPAREN genericLiteralList RPAREN
+	;
+
+traversalSourceSpawnMethod_V
+	: 'V' LPAREN genericLiteralList RPAREN
+	;
+
+traversalSourceSpawnMethod_inject
+    : 'inject' LPAREN genericLiteralList RPAREN
+    ;
+
+traversalSourceSpawnMethod_io
+    : 'io' LPAREN stringLiteral RPAREN
+    ;
+
+chainedTraversal
+    : traversalMethod
+    | chainedTraversal DOT traversalMethod
+    | chainedTraversal DOT chainedParentOfGraphTraversal
+    ;
+
+chainedParentOfGraphTraversal
+    : traversalSelfMethod
+    | chainedParentOfGraphTraversal DOT traversalSelfMethod
+    ;
+
+nestedTraversal
+    : rootTraversal
+    | chainedTraversal
+    | ANON_TRAVERSAL_ROOT DOT chainedTraversal
+    ;
+
+terminatedTraversal
+    : rootTraversal DOT traversalTerminalMethod
+    ;
+
+/*********************************************
+    GENERATED GRAMMAR - DO NOT CHANGE
+**********************************************/
+
+traversalMethod
+	: traversalMethod_V
+	| traversalMethod_addE
+	| traversalMethod_addV
+	| traversalMethod_aggregate
+	| traversalMethod_and
+	| traversalMethod_as
+	| traversalMethod_barrier
+	| traversalMethod_both
+	| traversalMethod_bothE
+	| traversalMethod_bothV
+	| traversalMethod_branch
+	| traversalMethod_by
+	| traversalMethod_cap
+	| traversalMethod_choose
+	| traversalMethod_coalesce
+	| traversalMethod_coin
+	| traversalMethod_connectedComponent
+	| traversalMethod_constant
+	| traversalMethod_count
+	| traversalMethod_cyclicPath
+	| traversalMethod_dedup
+	| traversalMethod_drop
+	| traversalMethod_elementMap
+	| traversalMethod_emit
+	| traversalMethod_filter
+	| traversalMethod_flatMap
+	| traversalMethod_fold
+	| traversalMethod_from
+	| traversalMethod_group
+	| traversalMethod_groupCount
+	| traversalMethod_has
+	| traversalMethod_hasId
+	| traversalMethod_hasKey
+	| traversalMethod_hasLabel
+	| traversalMethod_hasNot
+	| traversalMethod_hasValue
+	| traversalMethod_id
+	| traversalMethod_identity
+	| traversalMethod_in
+	| traversalMethod_inE
+	| traversalMethod_inV
+	| traversalMethod_index
+	| traversalMethod_inject
+	| traversalMethod_is
+	| traversalMethod_key
+	| traversalMethod_label
+	| traversalMethod_limit
+	| traversalMethod_local
+	| traversalMethod_loops
+	| traversalMethod_map
+	| traversalMethod_match
+	| traversalMethod_math
+	| traversalMethod_max
+	| traversalMethod_mean
+	| traversalMethod_min
+	| traversalMethod_not
+	| traversalMethod_option
+	| traversalMethod_optional
+	| traversalMethod_or
+	| traversalMethod_order
+	| traversalMethod_otherV
+	| traversalMethod_out
+	| traversalMethod_outE
+	| traversalMethod_outV
+	| traversalMethod_pageRank
+	| traversalMethod_path
+	| traversalMethod_peerPressure
+	| traversalMethod_profile
+	| traversalMethod_project
+	| traversalMethod_properties
+	| traversalMethod_property
+	| traversalMethod_propertyMap
+	| traversalMethod_range
+	| traversalMethod_read
+	| traversalMethod_repeat
+	| traversalMethod_sack
+	| traversalMethod_sample
+	| traversalMethod_select
+	| traversalMethod_shortestPath
+	| traversalMethod_sideEffect
+	| traversalMethod_simplePath
+	| traversalMethod_skip
+	| traversalMethod_store
+	| traversalMethod_subgraph
+	| traversalMethod_sum
+	| traversalMethod_tail
+	| traversalMethod_timeLimit
+	| traversalMethod_times
+	| traversalMethod_to
+	| traversalMethod_toE
+	| traversalMethod_toV
+	| traversalMethod_tree
+	| traversalMethod_unfold
+	| traversalMethod_union
+	| traversalMethod_until
+	| traversalMethod_value
+	| traversalMethod_valueMap
+	| traversalMethod_values
+	| traversalMethod_where
+	| traversalMethod_with
+	| traversalMethod_write
+	;
+traversalMethod_V
+	: 'V' LPAREN genericLiteralList RPAREN
+	;
+
+traversalMethod_addE
+	: 'addE' LPAREN stringLiteral RPAREN #traversalMethod_addE_String
+	| 'addE' LPAREN nestedTraversal RPAREN #traversalMethod_addE_Traversal
+	;
+
+traversalMethod_addV
+	: 'addV' LPAREN RPAREN #traversalMethod_addV_Empty
+	| 'addV' LPAREN stringLiteral RPAREN #traversalMethod_addV_String
+	| 'addV' LPAREN nullLiteral RPAREN #traversalMethod_addV_String        // null means use the default vertex label
+	| 'addV' LPAREN nestedTraversal RPAREN #traversalMethod_addV_Traversal
+	;
+
+traversalMethod_aggregate
+	: 'aggregate' LPAREN traversalScope COMMA stringLiteral RPAREN #traversalMethod_aggregate_Scope_String
+	| 'aggregate' LPAREN stringLiteral RPAREN #traversalMethod_aggregate_String
+	;
+
+traversalMethod_and
+	: 'and' LPAREN nestedTraversalList RPAREN
+	;
+
+traversalMethod_as
+	: 'as' LPAREN stringLiteral (COMMA stringLiteralList)? RPAREN
+	;
+
+traversalMethod_barrier
+	: 'barrier' LPAREN traversalSackMethod RPAREN #traversalMethod_barrier_Consumer
+	| 'barrier' LPAREN RPAREN #traversalMethod_barrier_Empty
+	| 'barrier' LPAREN integerLiteral RPAREN #traversalMethod_barrier_int
+	;
+
+traversalMethod_both
+	: 'both' LPAREN stringLiteralList RPAREN
+	;
+
+traversalMethod_bothE
+	: 'bothE' LPAREN stringLiteralList RPAREN
+	;
+
+traversalMethod_bothV
+	: 'bothV' LPAREN RPAREN
+	;
+
+traversalMethod_branch
+	: 'branch' LPAREN nestedTraversal RPAREN
+	;
+
+traversalMethod_by
+	: 'by' LPAREN traversalComparator RPAREN #traversalMethod_by_Comparator
+	| 'by' LPAREN RPAREN #traversalMethod_by_Empty
+	| 'by' LPAREN traversalFunction RPAREN #traversalMethod_by_Function
+	| 'by' LPAREN traversalFunction COMMA traversalComparator RPAREN #traversalMethod_by_Function_Comparator
+	| 'by' LPAREN traversalOrder RPAREN #traversalMethod_by_Order
+	| 'by' LPAREN stringLiteral RPAREN #traversalMethod_by_String
+	| 'by' LPAREN stringLiteral COMMA traversalComparator RPAREN #traversalMethod_by_String_Comparator
+	| 'by' LPAREN traversalToken RPAREN #traversalMethod_by_T
+	| 'by' LPAREN nestedTraversal RPAREN #traversalMethod_by_Traversal
+	| 'by' LPAREN nestedTraversal COMMA traversalComparator RPAREN #traversalMethod_by_Traversal_Comparator
+	;
+
+traversalMethod_cap
+	: 'cap' LPAREN stringLiteral (COMMA stringLiteralList)? RPAREN
+	;
+
+traversalMethod_choose
+	: 'choose' LPAREN traversalFunction RPAREN #traversalMethod_choose_Function
+	| 'choose' LPAREN traversalPredicate COMMA nestedTraversal RPAREN #traversalMethod_choose_Predicate_Traversal
+	| 'choose' LPAREN traversalPredicate COMMA nestedTraversal COMMA nestedTraversal RPAREN #traversalMethod_choose_Predicate_Traversal_Traversal
+	| 'choose' LPAREN nestedTraversal RPAREN #traversalMethod_choose_Traversal
+	| 'choose' LPAREN nestedTraversal COMMA nestedTraversal RPAREN #traversalMethod_choose_Traversal_Traversal
+	| 'choose' LPAREN nestedTraversal COMMA nestedTraversal COMMA nestedTraversal RPAREN #traversalMethod_choose_Traversal_Traversal_Traversal
+	;
+
+traversalMethod_coalesce
+	: 'coalesce' LPAREN nestedTraversalList RPAREN
+	;
+
+traversalMethod_coin
+	: 'coin' LPAREN floatLiteral RPAREN
+	;
+
+traversalMethod_connectedComponent
+	: 'connectedComponent' LPAREN RPAREN
+	;
+
+traversalMethod_constant
+	: 'constant' LPAREN genericLiteral RPAREN
+	;
+
+traversalMethod_count
+	: 'count' LPAREN RPAREN #traversalMethod_count_Empty
+	| 'count' LPAREN traversalScope RPAREN #traversalMethod_count_Scope
+	;
+
+traversalMethod_cyclicPath
+	: 'cyclicPath' LPAREN RPAREN
+	;
+
+traversalMethod_dedup
+	: 'dedup' LPAREN traversalScope (COMMA stringLiteralList)? RPAREN #traversalMethod_dedup_Scope_String
+	| 'dedup' LPAREN stringLiteralList RPAREN #traversalMethod_dedup_String
+	;
+
+traversalMethod_drop
+	: 'drop' LPAREN RPAREN
+	;
+
+traversalMethod_elementMap
+	: 'elementMap' LPAREN stringLiteralList RPAREN
+	;
+
+traversalMethod_emit
+	: 'emit' LPAREN RPAREN #traversalMethod_emit_Empty
+	| 'emit' LPAREN traversalPredicate RPAREN #traversalMethod_emit_Predicate
+	| 'emit' LPAREN nestedTraversal RPAREN #traversalMethod_emit_Traversal
+	;
+
+traversalMethod_filter
+	: 'filter' LPAREN traversalPredicate RPAREN #traversalMethod_filter_Predicate
+	| 'filter' LPAREN nestedTraversal RPAREN #traversalMethod_filter_Traversal
+	;
+
+traversalMethod_flatMap
+	: 'flatMap' LPAREN nestedTraversal RPAREN
+	;
+
+traversalMethod_fold
+	: 'fold' LPAREN RPAREN #traversalMethod_fold_Empty
+	| 'fold' LPAREN genericLiteral COMMA traversalBiFunction RPAREN #traversalMethod_fold_Object_BiFunction
+	;
+
+traversalMethod_from
+	: 'from' LPAREN stringLiteral RPAREN #traversalMethod_from_String
+	| 'from' LPAREN nestedTraversal RPAREN #traversalMethod_from_Traversal
+	;
+
+traversalMethod_group
+	: 'group' LPAREN RPAREN #traversalMethod_group_Empty
+	| 'group' LPAREN stringLiteral RPAREN #traversalMethod_group_String
+	;
+
+traversalMethod_groupCount
+	: 'groupCount' LPAREN RPAREN #traversalMethod_groupCount_Empty
+	| 'groupCount' LPAREN stringLiteral RPAREN #traversalMethod_groupCount_String
+	;
+
+traversalMethod_has
+	: 'has' LPAREN stringLiteral RPAREN #traversalMethod_has_String
+	| 'has' LPAREN stringLiteral COMMA genericLiteral RPAREN #traversalMethod_has_String_Object
+	| 'has' LPAREN stringLiteral COMMA traversalPredicate RPAREN #traversalMethod_has_String_P
+	| 'has' LPAREN stringLiteral COMMA stringLiteral COMMA genericLiteral RPAREN #traversalMethod_has_String_String_Object
+	| 'has' LPAREN stringLiteral COMMA stringLiteral COMMA traversalPredicate RPAREN #traversalMethod_has_String_String_P
+	| 'has' LPAREN stringLiteral COMMA nestedTraversal RPAREN #traversalMethod_has_String_Traversal
+	| 'has' LPAREN traversalToken COMMA genericLiteral RPAREN #traversalMethod_has_T_Object
+	| 'has' LPAREN traversalToken COMMA traversalPredicate RPAREN #traversalMethod_has_T_P
+	| 'has' LPAREN traversalToken COMMA nestedTraversal RPAREN #traversalMethod_has_T_Traversal
+	;
+
+traversalMethod_hasId
+	: 'hasId' LPAREN genericLiteral (COMMA genericLiteralList)? RPAREN #traversalMethod_hasId_Object_Object
+	| 'hasId' LPAREN traversalPredicate RPAREN #traversalMethod_hasId_P
+	;
+
+traversalMethod_hasKey
+	: 'hasKey' LPAREN traversalPredicate RPAREN #traversalMethod_hasKey_P
+	| 'hasKey' LPAREN stringLiteral (COMMA stringLiteralList)? RPAREN #traversalMethod_hasKey_String_String
+	;
+
+traversalMethod_hasLabel
+	: 'hasLabel' LPAREN traversalPredicate RPAREN #traversalMethod_hasLabel_P
+	| 'hasLabel' LPAREN stringLiteral (COMMA stringLiteralList)? RPAREN #traversalMethod_hasLabel_String_String
+	;
+
+traversalMethod_hasNot
+	: 'hasNot' LPAREN stringLiteral RPAREN
+	;
+
+traversalMethod_hasValue
+	: 'hasValue' LPAREN genericLiteral (COMMA genericLiteralList)? RPAREN #traversalMethod_hasValue_Object_Object
+	| 'hasValue' LPAREN traversalPredicate RPAREN #traversalMethod_hasValue_P
+	;
+
+traversalMethod_id
+	: 'id' LPAREN RPAREN
+	;
+
+traversalMethod_identity
+	: 'identity' LPAREN RPAREN
+	;
+
+traversalMethod_in
+	: 'in' LPAREN stringLiteralList RPAREN
+	;
+
+traversalMethod_inE
+	: 'inE' LPAREN stringLiteralList RPAREN
+	;
+
+traversalMethod_inV
+	: 'inV' LPAREN RPAREN
+	;
+
+traversalMethod_index
+	: 'index' LPAREN RPAREN
+	;
+
+traversalMethod_inject
+	: 'inject' LPAREN genericLiteralList RPAREN
+	;
+
+traversalMethod_is
+	: 'is' LPAREN genericLiteral RPAREN #traversalMethod_is_Object
+	| 'is' LPAREN traversalPredicate RPAREN #traversalMethod_is_P
+	;
+
+traversalMethod_key
+	: 'key' LPAREN RPAREN
+	;
+
+traversalMethod_label
+	: 'label' LPAREN RPAREN
+	;
+
+traversalMethod_limit
+	: 'limit' LPAREN traversalScope COMMA integerLiteral RPAREN #traversalMethod_limit_Scope_long
+	| 'limit' LPAREN integerLiteral RPAREN #traversalMethod_limit_long
+	;
+
+traversalMethod_local
+	: 'local' LPAREN nestedTraversal RPAREN
+	;
+
+traversalMethod_loops
+	: 'loops' LPAREN RPAREN #traversalMethod_loops_Empty
+	| 'loops' LPAREN stringLiteral RPAREN #traversalMethod_loops_String
+	;
+
+traversalMethod_map
+	: 'map' LPAREN nestedTraversal RPAREN
+	;
+
+traversalMethod_match
+	: 'match' LPAREN nestedTraversalList RPAREN
+	;
+
+traversalMethod_math
+	: 'math' LPAREN stringLiteral RPAREN
+	;
+
+traversalMethod_max
+	: 'max' LPAREN RPAREN #traversalMethod_max_Empty
+	| 'max' LPAREN traversalScope RPAREN #traversalMethod_max_Scope
+	;
+
+traversalMethod_mean
+	: 'mean' LPAREN RPAREN #traversalMethod_mean_Empty
+	| 'mean' LPAREN traversalScope RPAREN #traversalMethod_mean_Scope
+	;
+
+traversalMethod_min
+	: 'min' LPAREN RPAREN #traversalMethod_min_Empty
+	| 'min' LPAREN traversalScope RPAREN #traversalMethod_min_Scope
+	;
+
+traversalMethod_not
+	: 'not' LPAREN nestedTraversal RPAREN
+	;
+
+traversalMethod_option
+	: 'option' LPAREN traversalPredicate COMMA nestedTraversal RPAREN #traversalMethod_option_Predicate_Traversal
+	| 'option' LPAREN genericLiteral COMMA nestedTraversal RPAREN #traversalMethod_option_Object_Traversal
+	| 'option' LPAREN nestedTraversal RPAREN #traversalMethod_option_Traversal
+	;
+
+traversalMethod_optional
+	: 'optional' LPAREN nestedTraversal RPAREN
+	;
+
+traversalMethod_or
+	: 'or' LPAREN nestedTraversalList RPAREN
+	;
+
+traversalMethod_order
+	: 'order' LPAREN RPAREN #traversalMethod_order_Empty
+	| 'order' LPAREN traversalScope RPAREN #traversalMethod_order_Scope
+	;
+
+traversalMethod_otherV
+	: 'otherV' LPAREN RPAREN
+	;
+
+traversalMethod_out
+	: 'out' LPAREN stringLiteralList RPAREN
+	;
+
+traversalMethod_outE
+	: 'outE' LPAREN stringLiteralList RPAREN
+	;
+
+traversalMethod_outV
+	: 'outV' LPAREN RPAREN
+	;
+
+traversalMethod_pageRank
+	: 'pageRank' LPAREN RPAREN #traversalMethod_pageRank_Empty
+	| 'pageRank' LPAREN floatLiteral RPAREN #traversalMethod_pageRank_double
+	;
+
+traversalMethod_path
+	: 'path' LPAREN RPAREN
+	;
+
+traversalMethod_peerPressure
+	: 'peerPressure' LPAREN RPAREN
+	;
+
+traversalMethod_profile
+	: 'profile' LPAREN RPAREN #traversalMethod_profile_Empty
+	| 'profile' LPAREN stringLiteral RPAREN #traversalMethod_profile_String
+	;
+
+traversalMethod_project
+	: 'project' LPAREN stringLiteral (COMMA stringLiteralList)? RPAREN
+	;
+
+traversalMethod_properties
+	: 'properties' LPAREN stringLiteralList RPAREN
+	;
+
+traversalMethod_property
+	: 'property' LPAREN traversalCardinality COMMA genericLiteral COMMA genericLiteral (COMMA genericLiteralList)? RPAREN #traversalMethod_property_Cardinality_Object_Object_Object
+	| 'property' LPAREN genericLiteral COMMA genericLiteral (COMMA genericLiteralList)? RPAREN #traversalMethod_property_Object_Object_Object
+	;
+
+traversalMethod_propertyMap
+	: 'propertyMap' LPAREN stringLiteralList RPAREN
+	;
+
+traversalMethod_range
+	: 'range' LPAREN traversalScope COMMA integerLiteral COMMA integerLiteral RPAREN #traversalMethod_range_Scope_long_long
+	| 'range' LPAREN integerLiteral COMMA integerLiteral RPAREN #traversalMethod_range_long_long
+	;
+
+traversalMethod_read
+	: 'read' LPAREN RPAREN
+	;
+
+traversalMethod_repeat
+	: 'repeat' LPAREN stringLiteral COMMA nestedTraversal RPAREN #traversalMethod_repeat_String_Traversal
+	| 'repeat' LPAREN nestedTraversal RPAREN #traversalMethod_repeat_Traversal
+	;
+
+traversalMethod_sack
+	: 'sack' LPAREN traversalBiFunction RPAREN #traversalMethod_sack_BiFunction
+	| 'sack' LPAREN RPAREN #traversalMethod_sack_Empty
+	;
+
+traversalMethod_sample
+	: 'sample' LPAREN traversalScope COMMA integerLiteral RPAREN #traversalMethod_sample_Scope_int
+	| 'sample' LPAREN integerLiteral RPAREN #traversalMethod_sample_int
+	;
+
+traversalMethod_select
+	: 'select' LPAREN traversalColumn RPAREN #traversalMethod_select_Column
+	| 'select' LPAREN traversalPop COMMA stringLiteral RPAREN #traversalMethod_select_Pop_String
+	| 'select' LPAREN traversalPop COMMA stringLiteral COMMA stringLiteral (COMMA stringLiteralList)? RPAREN #traversalMethod_select_Pop_String_String_String
+	| 'select' LPAREN traversalPop COMMA nestedTraversal RPAREN #traversalMethod_select_Pop_Traversal
+	| 'select' LPAREN stringLiteral RPAREN #traversalMethod_select_String
+	| 'select' LPAREN stringLiteral COMMA stringLiteral (COMMA stringLiteralList)? RPAREN #traversalMethod_select_String_String_String
+	| 'select' LPAREN nestedTraversal RPAREN #traversalMethod_select_Traversal
+	;
+
+traversalMethod_shortestPath
+	: 'shortestPath' LPAREN RPAREN
+	;
+
+traversalMethod_sideEffect
+	: 'sideEffect' LPAREN nestedTraversal RPAREN
+	;
+
+traversalMethod_simplePath
+	: 'simplePath' LPAREN RPAREN
+	;
+
+traversalMethod_skip
+	: 'skip' LPAREN traversalScope COMMA integerLiteral RPAREN #traversalMethod_skip_Scope_long
+	| 'skip' LPAREN integerLiteral RPAREN #traversalMethod_skip_long
+	;
+
+traversalMethod_store
+	: 'store' LPAREN stringLiteral RPAREN
+	;
+
+traversalMethod_subgraph
+	: 'subgraph' LPAREN stringLiteral RPAREN
+	;
+
+traversalMethod_sum
+	: 'sum' LPAREN RPAREN #traversalMethod_sum_Empty
+	| 'sum' LPAREN traversalScope RPAREN #traversalMethod_sum_Scope
+	;
+
+traversalMethod_tail
+	: 'tail' LPAREN RPAREN #traversalMethod_tail_Empty
+	| 'tail' LPAREN traversalScope RPAREN #traversalMethod_tail_Scope
+	| 'tail' LPAREN traversalScope COMMA integerLiteral RPAREN #traversalMethod_tail_Scope_long
+	| 'tail' LPAREN integerLiteral RPAREN #traversalMethod_tail_long
+	;
+
+traversalMethod_timeLimit
+	: 'timeLimit' LPAREN integerLiteral RPAREN
+	;
+
+traversalMethod_times
+	: 'times' LPAREN integerLiteral RPAREN
+	;
+
+traversalMethod_to
+	: 'to' LPAREN traversalDirection (COMMA stringLiteralList)? RPAREN #traversalMethod_to_Direction_String
+	| 'to' LPAREN stringLiteral RPAREN #traversalMethod_to_String
+	| 'to' LPAREN nestedTraversal RPAREN #traversalMethod_to_Traversal
+	;
+
+traversalMethod_toE
+	: 'toE' LPAREN traversalDirection (COMMA stringLiteralList)? RPAREN
+	;
+
+traversalMethod_toV
+	: 'toV' LPAREN traversalDirection RPAREN
+	;
+
+traversalMethod_tree
+	: 'tree' LPAREN RPAREN #traversalMethod_tree_Empty
+	| 'tree' LPAREN stringLiteral RPAREN #traversalMethod_tree_String
+	;
+
+traversalMethod_unfold
+	: 'unfold' LPAREN RPAREN
+	;
+
+traversalMethod_union
+	: 'union' LPAREN nestedTraversalList RPAREN
+	;
+
+traversalMethod_until
+	: 'until' LPAREN traversalPredicate RPAREN #traversalMethod_until_Predicate
+	| 'until' LPAREN nestedTraversal RPAREN #traversalMethod_until_Traversal
+	;
+
+traversalMethod_value
+	: 'value' LPAREN RPAREN
+	;
+
+traversalMethod_valueMap
+	: 'valueMap' LPAREN stringLiteralList RPAREN #traversalMethod_valueMap_String
+	| 'valueMap' LPAREN booleanLiteral (COMMA stringLiteralList)? RPAREN #traversalMethod_valueMap_boolean_String
+	;
+
+traversalMethod_values
+	: 'values' LPAREN stringLiteralList RPAREN
+	;
+
+traversalMethod_where
+	: 'where' LPAREN traversalPredicate RPAREN #traversalMethod_where_P
+	| 'where' LPAREN stringLiteral COMMA traversalPredicate RPAREN #traversalMethod_where_String_P
+	| 'where' LPAREN nestedTraversal RPAREN #traversalMethod_where_Traversal
+	;
+
+traversalMethod_with
+	: 'with' LPAREN stringLiteral RPAREN #traversalMethod_with_String
+	| 'with' LPAREN stringLiteral COMMA genericLiteral RPAREN #traversalMethod_with_String_Object
+	;
+
+traversalMethod_write
+	: 'write' LPAREN RPAREN
+	;
+
+
+
+
+/*********************************************
+    ARGUMENT AND TERMINAL RULES
+**********************************************/
+
+traversalStrategy
+//  : 'ConnectiveStrategy' - not supported as it is a default strategy and we don't allow removal at this time
+//  | 'ElementIdStrategy' - not supported as the configuration takes a lambda
+//  | 'EventStrategy' - not supported as there is no way to send events back to the client
+//  | 'HaltedTraverserStrategy' - not supported as it is not typically relevant to OLTP
+//  | 'OptionsStrategy' - not supported as it's internal to with()
+    : 'new' 'PartitionStrategy' LPAREN traversalStrategyArgs_PartitionStrategy? (COMMA traversalStrategyArgs_PartitionStrategy)* RPAREN
+//  | 'RequirementStrategy' - not supported as it's internally relevant only
+//  | 'SackStrategy' - not supported directly as it's internal to withSack()
+    | 'new' 'SeedStrategy' LPAREN integerLiteral RPAREN
+//  | 'SideEffectStrategy' - not supported directly as it's internal to withSideEffect()
+    | 'new' 'SubgraphStrategy' LPAREN traversalStrategyArgs_SubgraphStrategy? (COMMA traversalStrategyArgs_SubgraphStrategy)* RPAREN
+//  | 'MatchAlgorithmStrategy' - not supported directly as it's internal to match()
+//  | 'ProfileStrategy' - not supported directly as it's internal to profile()
+//  | 'ReferenceElementStrategy' - not supported directly as users really can't/shouldn't change this in our context of a remote Gremlin provider
+//  | 'AdjacentToIncidentStrategy' - not supported as it is a default strategy and we don't allow removal at this time
+//  | 'ByModulatorOptimizationStrategy' - not supported as it is a default strategy and we don't allow removal at this time
+//  | 'CountStrategy' - not supported as it is a default strategy and we don't allow removal at this time
+//  | 'EarlyLimitStrategy' - not supported as it is a default strategy and we don't allow removal at this time
+//  | 'FilterRankingStrategy' - not supported as it is a default strategy and we don't allow removal at this time
+//  | 'IdentityRemovalStrategy' - not supported as it is a default strategy and we don't allow removal at this time
+//  | 'IncidentToAdjacentStrategy' - not supported as it is a default strategy and we don't allow removal at this time
+//  | 'InlineFilterStrategy' - not supported as it is a default strategy and we don't allow removal at this time
+//  | 'LazyBarrierStrategy' - not supported as it is a default strategy and we don't allow removal at this time
+//  | 'MatchPredicateStrategy' - not supported as it is a default strategy and we don't allow removal at this time
+//  | 'OrderLimitStrategy' - not supported as it is a default strategy and we don't allow removal at this time
+//  | 'PathProcessorStrategy' - not supported as it is a default strategy and we don't allow removal at this time
+//  | 'PathRetractionStrategy' - not supported as it is a default strategy and we don't allow removal at this time
+//  | 'RepeatUnrollStrategy' - not supported as it is a default strategy and we don't allow removal at this time
+//  | 'ComputerVerificationStrategy' - not supported since it's GraphComputer related
+    | 'new' 'EdgeLabelVerificationStrategy' LPAREN traversalStrategyArgs_EdgeLabelVerificationStrategy? (COMMA traversalStrategyArgs_EdgeLabelVerificationStrategy)* RPAREN
+//  | 'LambdaRestrictionStrategy' - not supported as we don't support lambdas in any situation
+    | 'ReadOnlyStrategy'
+    | 'new' 'ReservedKeysVerificationStrategy' LPAREN traversalStrategyArgs_ReservedKeysVerificationStrategy? (COMMA traversalStrategyArgs_ReservedKeysVerificationStrategy)* RPAREN
+//  | 'StandardVerificationStrategy' - not supported since this is an interal strategy
+    ;
+
+traversalStrategyArgs_PartitionStrategy
+    : 'includeMetaProperties' COLON booleanLiteral
+    | 'writePartition' COLON stringLiteral
+    | 'partitionKey' COLON stringLiteral
+    | 'readPartitions' COLON stringLiteralList
+    ;
+
+traversalStrategyArgs_SubgraphStrategy
+    : 'vertices' COLON nestedTraversal
+    | 'edges' COLON nestedTraversal
+    | 'vertexProperties' COLON nestedTraversal
+    | 'checkAdjacentVertices' COLON booleanLiteral
+    ;
+
+traversalStrategyArgs_EdgeLabelVerificationStrategy
+    : 'throwException' COLON booleanLiteral
+    | 'logWarning' COLON booleanLiteral
+    ;
+
+traversalStrategyArgs_ReservedKeysVerificationStrategy
+    : 'keys' COLON stringLiteralList
+    | 'throwException' COLON booleanLiteral
+    | 'logWarning' COLON booleanLiteral
+    ;
+
+traversalScope
+    : 'local' | 'Scope.local'
+    | 'global' | 'Scope.global'
+    ;
+
+traversalToken
+    : 'id' | 'T.id'
+    | 'label' | 'T.label'
+    | 'key' | 'T.key'
+    | 'value' | 'T.value'
+    ;
+
+traversalOrder
+    : 'incr' | 'Order.incr'
+    | 'decr' | 'Order.decr'
+    | 'asc'  | 'Order.asc'
+    | 'desc' | 'Order.desc'
+    | 'shuffle' | 'Order.shuffle'
+    ;
+
+traversalDirection
+    : 'IN' | 'Direction.IN'
+    | 'OUT' | 'Direction.OUT'
+    | 'BOTH' | 'Direction.BOTH'
+    ;
+
+traversalCardinality
+    : 'single' | 'Cardinality.single'
+    | 'set' | 'Cardinality.set'
+    | 'list' | 'Cardinality.list'
+    ;
+
+traversalColumn
+    : 'keys' | 'Column.keys'
+    | 'values' | 'Column.values'
+    ;
+
+traversalPop
+    : 'first' | 'Pop.first'
+    | 'last' | 'Pop.last'
+    | 'all' | 'Pop.all'
+    | 'mixed' | 'Pop.mixed'
+    ;
+
+traversalOperator
+    : 'addAll' | 'Operator.addAll'
+    | 'and' | 'Operator.and'
+    | 'assign' | 'Operator.assign'
+    | 'div' | 'Operator.div'
+    | 'max' | 'Operator.max'
+    | 'min' | 'Operator.min'
+    | 'minus' | 'Operator.minus'
+    | 'mult' | 'Operator.mult'
+    | 'or' | 'Operator.or'
+    | 'sum' | 'Operator.sum'
+    | 'sumLong' | 'Operator.sumLong'
+    ;
+
+traversalOptionParent
+    : 'any' | 'Pick.any'
+    | 'none' | 'Pick.none'
+    ;
+
+traversalPredicate
+    : traversalPredicate_eq
+    | traversalPredicate_neq
+    | traversalPredicate_lt
+    | traversalPredicate_lte
+    | traversalPredicate_gt
+    | traversalPredicate_gte
+    | traversalPredicate_inside
+    | traversalPredicate_outside
+    | traversalPredicate_between
+    | traversalPredicate_within
+    | traversalPredicate_without
+    | traversalPredicate_not
+    | traversalPredicate_startingWith
+    | traversalPredicate_notStartingWith
+    | traversalPredicate_endingWith
+    | traversalPredicate_notEndingWith
+    | traversalPredicate_containing
+    | traversalPredicate_notContaining
+    | traversalPredicate DOT 'and' LPAREN traversalPredicate RPAREN
+    | traversalPredicate DOT 'or' LPAREN traversalPredicate RPAREN
+    | traversalPredicate DOT 'negate' LPAREN RPAREN
+    ;
+
+traversalTerminalMethod
+    : traversalTerminalMethod_explain
+    | traversalTerminalMethod_iterate
+    | traversalTerminalMethod_hasNext
+    | traversalTerminalMethod_tryNext
+    | traversalTerminalMethod_next
+    | traversalTerminalMethod_toList
+    | traversalTerminalMethod_toSet
+    | traversalTerminalMethod_toBulkSet
+    ;
+
+traversalSackMethod
+    : 'normSack' | 'Barrier.normSack'
+    ;
+
+traversalSelfMethod
+    : traversalSelfMethod_none
+    ;
+
+// Additional special rules that are derived from above
+// These are used to restrict broad method signatures that accept lambdas
+// to a smaller set.
+traversalComparator
+    : traversalOrder
+    ;
+
+traversalFunction
+    : traversalToken
+    | traversalColumn
+    ;
+
+traversalBiFunction
+    : traversalOperator
+    ;
+
+traversalPredicate_eq
+    : ('P.eq' | 'eq') LPAREN genericLiteral RPAREN
+    ;
+
+traversalPredicate_neq
+    : ('P.neq' | 'neq') LPAREN genericLiteral RPAREN
+    ;
+
+traversalPredicate_lt
+    : ('P.lt' | 'lt') LPAREN genericLiteral RPAREN
+    ;
+
+traversalPredicate_lte
+    : ('P.lte' | 'lte') LPAREN genericLiteral RPAREN
+    ;
+
+traversalPredicate_gt
+    : ('P.gt' | 'gt') LPAREN genericLiteral RPAREN
+    ;
+
+traversalPredicate_gte
+    : ('P.gte' | 'gte') LPAREN genericLiteral RPAREN
+    ;
+
+traversalPredicate_inside
+    : ('P.inside' | 'inside') LPAREN genericLiteral COMMA genericLiteral RPAREN
+    ;
+
+traversalPredicate_outside
+    : ('P.outside' | 'outside') LPAREN genericLiteral COMMA genericLiteral RPAREN
+    ;
+
+traversalPredicate_between
+    : ('P.between' | 'between') LPAREN genericLiteral COMMA genericLiteral RPAREN
+    ;
+
+traversalPredicate_within
+    : ('P.within' | 'within') LPAREN genericLiteralList RPAREN
+    ;
+
+traversalPredicate_without
+    : ('P.without' | 'without') LPAREN genericLiteralList RPAREN
+    ;
+
+traversalPredicate_not
+    : ('P.not' | 'not') LPAREN traversalPredicate RPAREN
+    ;
+
+traversalPredicate_containing
+    : ('TextP.containing' | 'containing') LPAREN stringLiteral RPAREN
+    ;
+
+traversalPredicate_notContaining
+    : ('TextP.notContaining' | 'notContaining') LPAREN stringLiteral RPAREN
+    ;
+
+traversalPredicate_startingWith
+    : ('TextP.startingWith' | 'startingWith') LPAREN stringLiteral RPAREN
+    ;
+
+traversalPredicate_notStartingWith
+    : ('TextP.notStartingWith' | 'notStartingWith') LPAREN stringLiteral RPAREN
+    ;
+
+traversalPredicate_endingWith
+    : ('TextP.endingWith' | 'endingWith') LPAREN stringLiteral RPAREN
+    ;
+
+traversalPredicate_notEndingWith
+    : ('TextP.notEndingWith' | 'notEndingWith') LPAREN stringLiteral RPAREN
+    ;
+
+traversalTerminalMethod_explain
+    : 'explain' LPAREN RPAREN
+    ;
+
+traversalTerminalMethod_hasNext
+    : 'hasNext' LPAREN RPAREN
+    ;
+
+traversalTerminalMethod_iterate
+    : 'iterate' LPAREN RPAREN
+    ;
+
+traversalTerminalMethod_tryNext
+    : 'tryNext' LPAREN RPAREN
+    ;
+
+traversalTerminalMethod_next
+    : 'next' LPAREN RPAREN
+    | 'next' LPAREN integerLiteral RPAREN
+    ;
+
+traversalTerminalMethod_toList
+    : 'toList' LPAREN RPAREN
+    ;
+
+traversalTerminalMethod_toSet
+    : 'toSet' LPAREN RPAREN
+    ;
+
+traversalTerminalMethod_toBulkSet
+    : 'toBulkSet' LPAREN RPAREN
+    ;
+
+traversalSelfMethod_none
+    : 'none' LPAREN RPAREN
+    ;
+
+// Gremlin specific lexer rules
+
+gremlinStringConstants
+    : withOptionsStringConstants
+    | shortestPathStringConstants
+    | pageRankStringConstants
+    | peerPressureStringConstants
+    ;
+
+pageRankStringConstants
+    : gremlinStringConstants_pageRankStringConstants_edges
+    | gremlinStringConstants_pageRankStringConstants_times
+    | gremlinStringConstants_pageRankStringConstants_propertyName
+    ;
+
+peerPressureStringConstants
+    : gremlinStringConstants_peerPressureStringConstants_edges
+    | gremlinStringConstants_peerPressureStringConstants_times
+    | gremlinStringConstants_peerPressureStringConstants_propertyName
+    ;
+
+shortestPathStringConstants
+    : gremlinStringConstants_shortestPathStringConstants_target
+    | gremlinStringConstants_shortestPathStringConstants_edges
+    | gremlinStringConstants_shortestPathStringConstants_distance
+    | gremlinStringConstants_shortestPathStringConstants_maxDistance
+    | gremlinStringConstants_shortestPathStringConstants_includeEdges
+    ;
+
+withOptionsStringConstants
+    : gremlinStringConstants_withOptionsStringConstants_tokens
+    | gremlinStringConstants_withOptionsStringConstants_none
+    | gremlinStringConstants_withOptionsStringConstants_ids
+    | gremlinStringConstants_withOptionsStringConstants_labels
+    | gremlinStringConstants_withOptionsStringConstants_keys
+    | gremlinStringConstants_withOptionsStringConstants_values
+    | gremlinStringConstants_withOptionsStringConstants_all
+    | gremlinStringConstants_withOptionsStringConstants_indexer
+    | gremlinStringConstants_withOptionsStringConstants_list
+    | gremlinStringConstants_withOptionsStringConstants_map
+    ;
+
+gremlinStringConstants_pageRankStringConstants_edges
+    : pageRankStringConstant DOT 'edges'
+    ;
+
+gremlinStringConstants_pageRankStringConstants_times
+    : pageRankStringConstant DOT 'times'
+    ;
+
+gremlinStringConstants_pageRankStringConstants_propertyName
+    : pageRankStringConstant DOT 'propertyName'
+    ;
+
+gremlinStringConstants_peerPressureStringConstants_edges
+    : peerPressureStringConstant DOT 'edges'
+    ;
+
+gremlinStringConstants_peerPressureStringConstants_times
+    : peerPressureStringConstant DOT 'times'
+    ;
+
+gremlinStringConstants_peerPressureStringConstants_propertyName
+    : peerPressureStringConstant DOT 'propertyName'
+    ;
+
+gremlinStringConstants_shortestPathStringConstants_target
+    : shortestPathStringConstant DOT 'target'
+    ;
+
+gremlinStringConstants_shortestPathStringConstants_edges
+    : shortestPathStringConstant DOT 'edges'
+    ;
+
+gremlinStringConstants_shortestPathStringConstants_distance
+    : shortestPathStringConstant DOT 'distance'
+    ;
+
+gremlinStringConstants_shortestPathStringConstants_maxDistance
+    : shortestPathStringConstant DOT 'maxDistance'
+    ;
+
+gremlinStringConstants_shortestPathStringConstants_includeEdges
+    : shortestPathStringConstant DOT 'includeEdges'
+    ;
+
+gremlinStringConstants_withOptionsStringConstants_tokens
+    : withOptionsStringConstant DOT 'tokens'
+    ;
+
+gremlinStringConstants_withOptionsStringConstants_none
+    : withOptionsStringConstant DOT 'none'
+    ;
+
+gremlinStringConstants_withOptionsStringConstants_ids
+    : withOptionsStringConstant DOT 'ids'
+    ;
+
+gremlinStringConstants_withOptionsStringConstants_labels
+    : withOptionsStringConstant DOT 'labels'
+    ;
+
+gremlinStringConstants_withOptionsStringConstants_keys
+    : withOptionsStringConstant DOT 'keys'
+    ;
+
+gremlinStringConstants_withOptionsStringConstants_values
+    : withOptionsStringConstant DOT 'values'
+    ;
+
+gremlinStringConstants_withOptionsStringConstants_all
+    : withOptionsStringConstant DOT 'all'
+    ;
+
+gremlinStringConstants_withOptionsStringConstants_indexer
+    : withOptionsStringConstant DOT 'indexer'
+    ;
+
+gremlinStringConstants_withOptionsStringConstants_list
+    : withOptionsStringConstant DOT 'list'
+    ;
+
+gremlinStringConstants_withOptionsStringConstants_map
+    : withOptionsStringConstant DOT 'map'
+    ;
+
+pageRankStringConstant
+    : 'PageRank'
+    ;
+
+peerPressureStringConstant
+    : 'PeerPressure'
+    ;
+
+shortestPathStringConstant
+    : 'ShortestPath'
+    ;
+
+withOptionsStringConstant
+    : 'WithOptions'
+    ;
+
+traversalStrategyList
+    : traversalStrategyExpr?
+    ;
+
+traversalStrategyExpr
+    : traversalStrategy (COMMA traversalStrategy)*
+    ;
+
+nestedTraversalList
+    : nestedTraversalExpr?
+    ;
+
+nestedTraversalExpr
+    : nestedTraversal (COMMA nestedTraversal)*
+    ;
+
+genericLiteralList
+    : genericLiteralExpr?
+    ;
+
+genericLiteralExpr
+    : genericLiteral (COMMA genericLiteral)*
+    ;
+
+genericLiteralRange
+    : integerLiteral DOT DOT integerLiteral
+    | stringLiteral DOT DOT stringLiteral
+    ;
+
+genericLiteralCollection
+    : LBRACK (genericLiteral (COMMA genericLiteral)*)? RBRACK
+    ;
+
+stringLiteralList
+    : stringLiteralExpr?
+    | LBRACK stringLiteralExpr? RBRACK
+    ;
+
+stringLiteralExpr
+    : stringLiteral (COMMA stringLiteral)*
+    ;
+
+genericLiteral
+	: integerLiteral
+	| floatLiteral
+	| booleanLiteral
+	| stringLiteral
+	| dateLiteral
+	| nullLiteral
+	// Allow the generic literal to match specific gremlin tokens also
+	| traversalToken
+	| traversalCardinality
+	| traversalDirection
+	| traversalOptionParent
+	| genericLiteralCollection
+	| genericLiteralRange
+	| nestedTraversal
+	| terminatedTraversal
+	| genericLiteralMap
+	;
+
+genericLiteralMap
+  : LBRACK (genericLiteral)? COLON (genericLiteral)? (COMMA (genericLiteral)? COLON (genericLiteral)?)* RBRACK
+  ;
+
+integerLiteral
+    : IntegerLiteral
+    ;
+
+floatLiteral
+    : FloatingPointLiteral
+    ;
+
+booleanLiteral
+    : BooleanLiteral
+    ;
+
+stringLiteral
+    : NonEmptyStringLiteral
+    | EmptyStringLiteral
+    | gremlinStringConstants
+    ;
+
+dateLiteral
+    : 'datetime' LPAREN stringLiteral RPAREN
+    ;
+
+nullLiteral
+    : NullLiteral
+    ;
+
+/*********************************************
+    LEXER RULES
+**********************************************/
+
+// Lexer rules
+// These rules are extracted from Java ANTLRv4 Grammar.
+// Source: https://github.com/antlr/grammars-v4/blob/master/java8/Java8.g4
+
+// §3.9 Keywords
+
+NEW : 'new';
+
+// Integer Literals
+
+IntegerLiteral
+	:	Sign? DecimalIntegerLiteral
+	|	Sign? HexIntegerLiteral
+	|	Sign? OctalIntegerLiteral
+	;
+
+fragment
+DecimalIntegerLiteral
+	:	DecimalNumeral IntegerTypeSuffix?
+	;
+
+fragment
+HexIntegerLiteral
+	:	HexNumeral IntegerTypeSuffix?
+	;
+
+fragment
+OctalIntegerLiteral
+	:	OctalNumeral IntegerTypeSuffix?
+	;
+
+fragment
+IntegerTypeSuffix
+	:	[lL]
+	;
+
+fragment
+DecimalNumeral
+	:	'0'
+	|	NonZeroDigit (Digits? | Underscores Digits)
+	;
+
+fragment
+Digits
+	:	Digit (DigitsAndUnderscores? Digit)?
+	;
+
+fragment
+Digit
+	:	'0'
+	|	NonZeroDigit
+	;
+
+fragment
+NonZeroDigit
+	:	[1-9]
+	;
+
+fragment
+DigitsAndUnderscores
+	:	DigitOrUnderscore+
+	;
+
+fragment
+DigitOrUnderscore
+	:	Digit
+	|	'_'
+	;
+
+fragment
+Underscores
+	:	'_'+
+	;
+
+fragment
+HexNumeral
+	:	'0' [xX] HexDigits
+	;
+
+fragment
+HexDigits
+	:	HexDigit (HexDigitsAndUnderscores? HexDigit)?
+	;
+
+fragment
+HexDigit
+	:	[0-9a-fA-F]
+	;
+
+fragment
+HexDigitsAndUnderscores
+	:	HexDigitOrUnderscore+
+	;
+
+fragment
+HexDigitOrUnderscore
+	:	HexDigit
+	|	'_'
+	;
+
+fragment
+OctalNumeral
+	:	'0' Underscores? OctalDigits
+	;
+
+fragment
+OctalDigits
+	:	OctalDigit (OctalDigitsAndUnderscores? OctalDigit)?
+	;
+
+fragment
+OctalDigit
+	:	[0-7]
+	;
+
+fragment
+OctalDigitsAndUnderscores
+	:	OctalDigitOrUnderscore+
+	;
+
+fragment
+OctalDigitOrUnderscore
+	:	OctalDigit
+	|	'_'
+	;
+
+// Floating-Point Literals
+
+FloatingPointLiteral
+	:	Sign? DecimalFloatingPointLiteral
+	;
+
+fragment
+DecimalFloatingPointLiteral
+    :   Digits ('.' Digits ExponentPart? | ExponentPart) FloatTypeSuffix?
+	|	Digits FloatTypeSuffix
+	;
+
+fragment
+ExponentPart
+	:	ExponentIndicator SignedInteger
+	;
+
+fragment
+ExponentIndicator
+	:	[eE]
+	;
+
+fragment
+SignedInteger
+	:	Sign? Digits
+	;
+
+fragment
+Sign
+	:	[+-]
+	;
+
+fragment
+FloatTypeSuffix
+	:	[fFdD]
+	;
+
+// Boolean Literals
+
+BooleanLiteral
+	:	'true'
+	|	'false'
+	;
+
+// Null Literal
+
+NullLiteral
+	:	'null'
+	;
+
+// String Literals
+
+// String literal is customized since Java only allows double quoted strings where Groovy supports single quoted
+// literals also. A side effect of this is ANTLR will not be able to parse single character string literals with
+// single quoted so we instead remove char literal altogether and only have string literal in lexer tokens.
+NonEmptyStringLiteral
+	:   '"' DoubleQuotedStringCharacters '"'
+	|   '\'' SingleQuotedStringCharacters '\''
+	;
+
+// We define NonEmptyStringLiteral and EmptyStringLiteral separately so that we can unambiguously handle empty queries
+EmptyStringLiteral
+	:   '""'
+	|   '\'\''
+	;
+
+fragment
+DoubleQuotedStringCharacters
+	:	DoubleQuotedStringCharacter+
+	;
+
+fragment
+DoubleQuotedStringCharacter
+	:	~('"' | '\\')
+	|   JoinLineEscape
+	|	EscapeSequence
+	;
+
+fragment
+SingleQuotedStringCharacters
+	:	SingleQuotedStringCharacter+
+	;
+
+fragment
+SingleQuotedStringCharacter
+	:	~('\'' | '\\')
+	|   JoinLineEscape
+	|	EscapeSequence
+	;
+
+// Escape Sequences for Character and String Literals
+fragment JoinLineEscape
+    : '\\' '\r'? '\n'
+    ;
+
+fragment
+EscapeSequence
+	:	'\\' [btnfr"'\\]
+	|	OctalEscape
+    |   UnicodeEscape // This is not in the spec but prevents having to preprocess the input
+	;
+
+fragment
+OctalEscape
+	:	'\\' OctalDigit
+	|	'\\' OctalDigit OctalDigit
+	|	'\\' ZeroToThree OctalDigit OctalDigit
+	;
+
+fragment
+ZeroToThree
+	:	[0-3]
+	;
+
+// This is not in the spec but prevents having to preprocess the input
+fragment
+UnicodeEscape
+    :   '\\' 'u'+  HexDigit HexDigit HexDigit HexDigit
+    ;
+
+// Separators
+
+LPAREN : '(';
+RPAREN : ')';
+LBRACE : '{';
+RBRACE : '}';
+LBRACK : '[';
+RBRACK : ']';
+SEMI : ';';
+COMMA : ',';
+DOT : '.';
+COLON : ':';
+
+TRAVERSAL_ROOT:     'g';
+ANON_TRAVERSAL_ROOT:     '__';
+
+// Trim whitespace and comments if present
+
+WS  :  [ \t\r\n\u000C]+ -> skip
+    ;
+
+LINE_COMMENT
+    :   '//' ~[\r\n]* -> skip
+    ;
diff --git a/gremlin-language/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/AbstractGrammarTest.java b/gremlin-language/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/AbstractGrammarTest.java
new file mode 100644
index 0000000..995e5b6
--- /dev/null
+++ b/gremlin-language/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/AbstractGrammarTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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.language.grammar;
+
+import org.antlr.v4.runtime.*;
+import org.antlr.v4.runtime.atn.PredictionMode;
+import org.apache.commons.lang3.exception.ExceptionUtils;
+
+import static org.junit.Assert.fail;
+
+public class AbstractGrammarTest {
+
+    protected void parse(final String query) {
+        parse(query, false);
+    }
+
+    protected void parse(final String query, final boolean expectFailures) {
+        try {
+            final CharStream in = CharStreams.fromString(query);
+            final GremlinLexer lexer = new GremlinLexer(in);
+            lexer.removeErrorListeners();
+            lexer.addErrorListener(new GremlinErrorListener());
+
+            final CommonTokenStream tokens = new CommonTokenStream(lexer);
+
+            // Setup error handler on parser
+            final GremlinParser parser = new GremlinParser(tokens);
+            parser.setErrorHandler(new BailErrorStrategy());
+            parser.getInterpreter().setPredictionMode(PredictionMode.SLL);
+
+            // Visit top level query
+            try {
+                final GremlinVisitor<GremlinParser.QueryListContext> visitor = new GremlinBaseVisitor<>();
+                visitor.visit(parser.queryList());
+            } catch (Exception ex) {
+                // Retry parsing the query again with using LL prediction mode.  LL parsing mode is more powerful
+                // so retrying the parsing would help parsing the rare edge cases.
+                tokens.seek(0); // rewind input stream
+                lexer.reset();
+                parser.reset();
+                parser.getInterpreter().setPredictionMode(PredictionMode.LL);
+
+                final GremlinVisitor<GremlinParser.QueryListContext> visitor = new GremlinBaseVisitor<>();
+                visitor.visit(parser.queryList());
+            }
+
+            // If we are expecting failures, put assert check here
+            if (expectFailures) {
+                fail("Query parsing should have failed for " + query);
+            }
+
+        } catch(Exception e) {
+            if (!expectFailures) {
+                final Throwable t = ExceptionUtils.getRootCause(e);
+                if (t instanceof LexerNoViableAltException) {
+                    fail(String.format("Error parsing query: %s - [%s] - failed at index: %s",
+                            query, t.toString(), ((LexerNoViableAltException) t).getStartIndex()));
+                } else if (t instanceof NoViableAltException) {
+                    fail(String.format("Error parsing query: %s - [%s]", query, ((NoViableAltException) t).getStartToken().toString()));
+                } else {
+                    fail(String.format("Error parsing query: %s - [%s]", query, t.getMessage()));
+                }
+            }
+        }
+    }
+
+}
+
diff --git a/gremlin-language/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/BasicGrammarTest.java b/gremlin-language/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/BasicGrammarTest.java
new file mode 100644
index 0000000..14dc2ac
--- /dev/null
+++ b/gremlin-language/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/BasicGrammarTest.java
@@ -0,0 +1,31 @@
+/*
+ * 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.language.grammar;
+
+import org.junit.Test;
+
+/**
+ * Basic smoke testing of the parser.
+ */
+public class BasicGrammarTest extends AbstractGrammarTest {
+    @Test
+    public void shouldParseV() {
+        parse("g.V()");
+    }
+}
diff --git a/gremlin-language/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/DocumentationReader.java b/gremlin-language/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/DocumentationReader.java
new file mode 100644
index 0000000..93bbccd
--- /dev/null
+++ b/gremlin-language/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/DocumentationReader.java
@@ -0,0 +1,122 @@
+/*
+ * 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.language.grammar;
+
+import org.apache.commons.text.StringEscapeUtils;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.*;
+import java.util.regex.Pattern;
+
+/**
+ * Reads asciidoc documentation for Gremlin snippets to help build the testing corpus.
+ */
+public class DocumentationReader {
+    private static final Pattern sourceCodePattern = Pattern.compile("\\[gremlin-groovy.*\\].*");
+    private static final Pattern startGremlinPattern = Pattern.compile("^g\\..*");
+
+    /**
+     * Some Gremlin in documentation is just not going to parse.
+     */
+    private static final Set<String> throwAway = new HashSet<>(Arrays.asList("g.inject(g.withComputer().V().shortestPath().with(ShortestPath.distance, 'weight').with(ShortestPath.includeEdges, true).with(ShortestPath.maxDistance, 1).toList().toArray()).map(unfold().values('name','weight').fold())"));
+
+    public static Set<String> parse(final String projectRoot) throws IOException {
+        final Set<String> gremlins = new LinkedHashSet<>();
+        Files.find(Paths.get(projectRoot, "docs", "src"),
+                Integer.MAX_VALUE,
+                (filePath, fileAttr) -> fileAttr.isRegularFile() && (filePath.toString().endsWith("traversal.asciidoc") || filePath.toString().contains("recipes"))).
+                sorted().
+                forEach(f -> {
+                    String currentGremlin = "";
+                    int openSnippet = 0;
+
+                    try {
+                        final List<String> lines = Files.readAllLines(f, StandardCharsets.UTF_8);
+                        for (String line : lines) {
+                            // trim and remove callouts
+                            String cleanLine = line.replaceAll("<\\d>", "").trim();
+
+                            // remove line comments
+                            int pos = cleanLine.indexOf("//");
+                            if (pos > 0) cleanLine = cleanLine.substring(0, pos).trim();
+
+                            if (sourceCodePattern.matcher(cleanLine).matches() || (openSnippet > 0 && cleanLine.equals("----"))) {
+                                if (openSnippet > 1) {
+                                    openSnippet = 0;
+                                } else {
+                                    openSnippet++;
+                                }
+                            } else if (openSnippet > 0 && (startGremlinPattern.matcher(cleanLine).matches() || isTerminated(currentGremlin))) {
+                                // new line of Gremlin that starts with g.
+                                currentGremlin += cleanLine;
+
+                                // line doesn't continue if there is no period or open paren
+                                if (!isTerminated(currentGremlin)) {
+                                    final String gremlinToAdd = replaceVariables(currentGremlin.trim());
+                                    if (!throwAway.contains(gremlinToAdd))
+                                        gremlins.add(gremlinToAdd);
+                                    currentGremlin = "";
+                                }
+                            }
+                        }
+                    } catch (IOException ioe) {
+                        throw new RuntimeException(ioe);
+                    }
+                });
+
+        return gremlins;
+    }
+
+    private static boolean isTerminated(final String gremlin) {
+        return gremlin.endsWith(".") || gremlin.endsWith("(") || gremlin.endsWith(",");
+    }
+
+    /**
+     * Variables can't be parsed by the grammar so they must be replaced with something concrete.
+     */
+    private static String replaceVariables(final String gremlin) {
+        // convert lambda vars to closures and they will be ignored by the test suite
+        return gremlin.replace("relations", "\"relations\"").
+                replace("places.size()", "6").
+                replace("places", "\"places\"").
+                replace("ids", "\"ids\"").
+                replace("vRexsterJob1", "\"rj1\"").
+                replace("vBlueprintsJob1", "\"bj1\"").
+                replace("weightFilter.clone()", "{it}").
+                replace("weightFilter", "{it}").
+                replace("vBob", "\"bob\"").
+                replace("vMarko", "\"marko\"").
+                replace("vPeter", "\"peter\"").
+                replace("vStephen", "\"stephen\"").
+                replace("input.head()", "\"head\"").
+                replace("input.tail().size()", "6").
+                replace("input.tail()", "\"tail\"").
+                replace("System.out.&println", "{it}").
+                replace("persons", "\"persons\"").
+                replace("marko.value('age')", "11").
+                replace("seedStrategy", "new SeedStrategy(99999)").
+                replace(".getClass()", "").
+                replace("result.toArray()", "4").
+                replace("vA.value('amount')", "0.0").
+                replace("vA", "\"vA\"");
+    }
+}
diff --git a/gremlin-language/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/FeatureReader.java b/gremlin-language/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/FeatureReader.java
new file mode 100644
index 0000000..6006c7b
--- /dev/null
+++ b/gremlin-language/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/FeatureReader.java
@@ -0,0 +1,95 @@
+/*
+ * 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.language.grammar;
+
+import org.apache.commons.text.StringEscapeUtils;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Reads the feature files and extracts Gremlin to help build the parsing test corpus.
+ */
+public class FeatureReader {
+
+    public static Set<String> parse(final String projectRoot) throws IOException {
+        final Set<String> gremlins = new LinkedHashSet<>();
+        Files.find(Paths.get(projectRoot, "gremlin-test", "features"),
+                   Integer.MAX_VALUE,
+                (filePath, fileAttr) -> fileAttr.isRegularFile() && filePath.toString().endsWith(".feature")).
+                sorted().
+                forEach(f -> {
+                    String currentGremlin = "";
+                    boolean openTriples = false;
+                    boolean skipIgnored = false;
+
+                    try {
+                        final List<String> lines = Files.readAllLines(f, StandardCharsets.UTF_8);
+                        for (String line : lines) {
+                            String cleanLine = line.trim();
+                            if (cleanLine.startsWith("Then nothing should happen because")) {
+                                skipIgnored = true;
+                            } else if (cleanLine.startsWith("And the graph should return")) {
+                                gremlins.add(replaceVariables(
+                                        StringEscapeUtils.unescapeJava(
+                                                cleanLine.substring(cleanLine.indexOf("\"") + 1, cleanLine.lastIndexOf("\"")))));
+                            } else if (cleanLine.startsWith("\"\"\"")) {
+                                openTriples = !openTriples;
+                                if (!skipIgnored && !openTriples) {
+                                    gremlins.add(replaceVariables(currentGremlin));
+                                    currentGremlin = "";
+                                }
+                            } else if (openTriples && !skipIgnored) {
+                                currentGremlin += cleanLine;
+                            }
+                        }
+                    } catch (IOException ioe) {
+                        throw new RuntimeException(ioe);
+                    }
+                });
+
+        return gremlins;
+    }
+
+    /**
+     * Variables can't be parsed by the grammar so they must be replaced with something concrete.
+     */
+    private static String replaceVariables(final String gremlin) {
+        return gremlin.replace("xx1", "\"1\"").
+                replace("xx2", "\"2\"").
+                replace("xx3", "\"3\"").
+                replace("vid1", "1").
+                replace("vid2", "2").
+                replace("vid3", "3").
+                replace("vid4", "4").
+                replace("vid5", "5").
+                replace("vid6", "6").
+                replace("eid7", "7").
+                replace("eid8", "8").
+                replace("eid9", "9").
+                replace("eid10", "10").
+                replace("eid11", "11").
+                replace("eid12", "12");
+    }
+}
diff --git a/gremlin-language/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinErrorListener.java b/gremlin-language/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinErrorListener.java
new file mode 100644
index 0000000..2c6bfc8
--- /dev/null
+++ b/gremlin-language/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinErrorListener.java
@@ -0,0 +1,33 @@
+/*
+ * 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.language.grammar;
+
+import org.antlr.v4.runtime.BaseErrorListener;
+import org.antlr.v4.runtime.RecognitionException;
+import org.antlr.v4.runtime.Recognizer;
+import org.antlr.v4.runtime.misc.ParseCancellationException;
+
+public class GremlinErrorListener extends BaseErrorListener {
+
+    @Override
+    public void syntaxError(final Recognizer<?, ?> recognizer, final Object offendingSymbol, final int line,
+                            final int charPositionInLine, final String msg, final RecognitionException e) {
+        throw new ParseCancellationException(e);
+    }
+}
diff --git a/gremlin-language/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/NegativeGrammarTest.java b/gremlin-language/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/NegativeGrammarTest.java
new file mode 100644
index 0000000..636fba3
--- /dev/null
+++ b/gremlin-language/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/NegativeGrammarTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.language.grammar;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(Parameterized.class)
+public class NegativeGrammarTest extends AbstractGrammarTest {
+
+    @Parameterized.Parameters
+    public static Iterable<String> queries() throws IOException {
+        final InputStream stream = ReferenceGrammarTest.class.getClassLoader()
+                .getResourceAsStream("incorrect-traversals.txt");
+
+        final List<String> queries = new ArrayList<>();
+        try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream))) {
+            String line;
+            while ((line = reader.readLine()) != null) {
+                queries.add(line);
+            }
+        }
+
+        return queries;
+    }
+
+    @Parameterized.Parameter
+    public String query;
+
+    @Test
+    public void test_parse() {
+        parse(query, true);
+    }
+
+
+}
diff --git a/gremlin-language/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/ReferenceGrammarTest.java b/gremlin-language/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/ReferenceGrammarTest.java
new file mode 100644
index 0000000..a2bbc06
--- /dev/null
+++ b/gremlin-language/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/ReferenceGrammarTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.language.grammar;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.IOException;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assume.assumeThat;
+
+/**
+ * Builds a corpus of Gremlin statements from Recipes, "The Traversal" in Reference Documentation and the Gherkin
+ * test suite and passes them all through the grammar parser.
+ */
+@RunWith(Parameterized.class)
+public class ReferenceGrammarTest extends AbstractGrammarTest {
+
+    private static final Pattern vertexPattern = Pattern.compile(".*v\\d.*");
+    private static final Pattern edgePattern = Pattern.compile(".*e\\d.*");
+
+    @Parameterized.Parameters(name = "{0}")
+    public static Iterable<String> queries() throws IOException {
+        final Set<String> gremlins = new LinkedHashSet<>(DocumentationReader.parse("../"));
+        gremlins.addAll(FeatureReader.parse("../"));
+        return gremlins;
+    }
+
+    @Parameterized.Parameter
+    public String query;
+
+    @Test
+    public void test_parse() {
+        assumeThat("Lambdas are not supported", query.contains("l1"), is(false));
+        assumeThat("Lambdas are not supported", query.contains("l2"), is(false));
+        assumeThat("Lambdas are not supported", query.contains("pred1"), is(false));
+        assumeThat("Lambdas are not supported", query.contains("c1"), is(false));
+        assumeThat("Lambdas are not supported", query.contains("c2"), is(false));
+        assumeThat("Lambdas are not supported", query.contains("Lambda.function("), is(false));
+        // start of a closure
+        assumeThat("Lambdas are not supported", query.contains("{"), is(false));
+        assumeThat("withComputer() step is not supported", query.startsWith("g.withComputer("), is(false));
+        assumeThat("io() step is not supported", query.startsWith("g.io("), is(false));
+        assumeThat("Vertex instances are not supported", vertexPattern.matcher(query).matches(), is(false));
+        assumeThat("Edge instances are not supported", edgePattern.matcher(query).matches(), is(false));
+        assumeThat("fill() terminator is not supported", query.contains("fill("), is(false));
+        assumeThat("connectedComponent() is not fully supported - needs tokens", query.contains("connectedComponent("), is(false));
+        assumeThat("withoutStrategies() is not supported", query.contains("withoutStrategies("), is(false));
+        assumeThat("program() is not supported", query.contains("program("), is(false));
+
+        parse(query);
+    }
+}
diff --git a/gremlin-language/src/test/resources/incorrect-traversals.txt b/gremlin-language/src/test/resources/incorrect-traversals.txt
new file mode 100644
index 0000000..4aa769b
--- /dev/null
+++ b/gremlin-language/src/test/resources/incorrect-traversals.txt
@@ -0,0 +1,22 @@
+g.addVertex()
+g.V();---
+g.VVV()
+g.tx().error()
+;;
+
+something something error
+h.V()
+V()
+addV()
+tx().commit()
+g.next()
+g.hasNext()
+g.V().repeat(g).times(10)
+g.V().repeat(g.V().next()).times(10)
+' '
+"  "
+g.V().has("person","name", startingWith(1234)).id()
+g.V('3').oute().limit(1)
+g.V('3').dedupe()
+g.V().order().bye('code').limit(1)
+g.V().horder().by(id)
\ No newline at end of file
diff --git a/gremlin-python/build/generate.groovy b/gremlin-python/build/generate.groovy
new file mode 100644
index 0000000..05507d5
--- /dev/null
+++ b/gremlin-python/build/generate.groovy
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph
+import org.apache.tinkerpop.gremlin.process.traversal.translator.PythonTranslator
+import org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine
+import org.apache.tinkerpop.gremlin.groovy.jsr223.ast.VarAsBindingASTTransformation
+import org.apache.tinkerpop.gremlin.groovy.jsr223.ast.RepeatASTTransformationCustomizer
+import org.apache.tinkerpop.gremlin.groovy.jsr223.GroovyCustomizer
+import org.codehaus.groovy.control.customizers.CompilationCustomizer
+import org.apache.tinkerpop.gremlin.features.FeatureReader
+
+import javax.script.SimpleBindings
+
+import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal
+
+// file is overwritten on each generation
+radishGremlinFile = new File("${projectBaseDir}/gremlin-python/src/main/python/radish/gremlin.py")
+
+// assumes globally unique scenario names for keys with list of Gremlin traversals as they appear
+gremlins = FeatureReader.parse("${projectBaseDir}")
+
+gremlinGroovyScriptEngine = new GremlinGroovyScriptEngine(new GroovyCustomizer() {
+    public CompilationCustomizer create() {
+        return new RepeatASTTransformationCustomizer(new VarAsBindingASTTransformation())
+    }
+})
+translator = PythonTranslator.of('g')
+g = traversal().withGraph(EmptyGraph.instance())
+bindings = new SimpleBindings()
+bindings.put('g', g)
+
+radishGremlinFile.withWriter('UTF-8') { Writer writer ->
+    writer.writeLine('#\n' +
+            '# Licensed to the Apache Software Foundation (ASF) under one\n' +
+            '# or more contributor license agreements.  See the NOTICE file\n' +
+            '# distributed with this work for additional information\n' +
+            '# regarding copyright ownership.  The ASF licenses this file\n' +
+            '# to you under the Apache License, Version 2.0 (the\n' +
+            '# "License"); you may not use this file except in compliance\n' +
+            '# with the License.  You may obtain a copy of the License at\n' +
+            '# \n' +
+            '# http://www.apache.org/licenses/LICENSE-2.0\n' +
+            '# \n' +
+            '# Unless required by applicable law or agreed to in writing,\n' +
+            '# software distributed under the License is distributed on an\n' +
+            '# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n' +
+            '# KIND, either express or implied.  See the License for the\n' +
+            '# specific language governing permissions and limitations\n' +
+            '# under the License.\n' +
+            '#\n')
+
+    writer.writeLine("\n\n#######################################################################################")
+    writer.writeLine("## Do NOT edit this file directly - generated by build/generate.groovy")
+    writer.writeLine("#######################################################################################\n\n")
+
+    writer.writeLine(
+                    'from radish import world\n' +
+                    'from gremlin_python.process.anonymous_traversal import traversal\n' +
+                    'from gremlin_python.process.traversal import TraversalStrategy\n' +
+                    'from gremlin_python.process.graph_traversal import __\n' +
+                    'from gremlin_python.structure.graph import Graph\n' +
+                    'from gremlin_python.process.traversal import Barrier, Cardinality, P, TextP, Pop, Scope, Column, Order, Direction, T, Pick, Operator, IO, WithOptions\n')
+    writer.writeLine('world.gremlins = {')
+    gremlins.each { k,v ->
+        writer.write("    '")
+        writer.write(k)
+        writer.write("': [")
+        def collected = v.collect{
+            def t = gremlinGroovyScriptEngine.eval(it, bindings)
+            [t, t.bytecode.bindings.keySet()]
+        }
+        def uniqueBindings = collected.collect{it[1]}.flatten().unique()
+        def gremlinItty = collected.iterator()
+        while (gremlinItty.hasNext()) {
+            def t = gremlinItty.next()[0]
+            writer.write("(lambda g")
+            if (!uniqueBindings.isEmpty()) {
+                writer.write(", ")
+                writer.write(uniqueBindings.join("=None,"))
+                writer.write("=None")
+            }
+            writer.write(":")
+            writer.write(translator.translate(t.bytecode).script)
+            writer.write(")")
+            if (gremlinItty.hasNext()) writer.write(', ')
+        }
+        writer.writeLine('], ')
+    }
+    writer.writeLine('}')
+}
+
+
diff --git a/gremlin-python/glv/GraphTraversalSource.template b/gremlin-python/glv/GraphTraversalSource.template
deleted file mode 100644
index 73017d2..0000000
--- a/gremlin-python/glv/GraphTraversalSource.template
+++ /dev/null
@@ -1,231 +0,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.
-#
-
-import sys
-import copy
-from .traversal import Traversal
-from .traversal import TraversalStrategies
-from .strategies import VertexProgramStrategy, OptionsStrategy
-from .traversal import Bytecode
-from ..driver.remote_connection import RemoteStrategy
-from .. import statics
-from ..statics import long
-
-
-class GraphTraversalSource(object):
-    def __init__(self, graph, traversal_strategies, bytecode=None):
-        self.graph = graph
-        self.traversal_strategies = traversal_strategies
-        if bytecode is None:
-          bytecode = Bytecode()
-        self.bytecode = bytecode
-        self.graph_traversal = GraphTraversal
-
-    def __repr__(self):
-        return "graphtraversalsource[" + str(self.graph) + "]"
-
-    def get_graph_traversal_source(self):
-        return self.__class__(self.graph, TraversalStrategies(self.traversal_strategies), Bytecode(self.bytecode))
-
-    def get_graph_traversal(self):
-        return self.graph_traversal(self.graph, self.traversal_strategies, Bytecode(self.bytecode))
-<% sourceStepMethods.each{ method -> %>
-    def <%= method %>(self, *args):
-        source = self.get_graph_traversal_source()
-        source.bytecode.add_source("<%= toJava.call(method) %>", *args)
-        return source
-<% } %>
-    def with_(self, k, v=None):
-        source = self.get_graph_traversal_source()
-        options_strategy = next((x for x in source.bytecode.source_instructions
-                                if x[0] == "withStrategies" and type(x[1]) is OptionsStrategy), None)
-
-        val = True if v is None else v
-        if options_strategy is None:
-            options_strategy = OptionsStrategy({k: val})
-            source = self.withStrategies(options_strategy)
-        else:
-            options_strategy[1].configuration[k] = val
-
-        return source
-
-    def withRemote(self, remote_connection):
-        source = self.get_graph_traversal_source()
-        source.traversal_strategies.add_strategies([RemoteStrategy(remote_connection)])
-        return source
-
-    def withComputer(self, graph_computer=None, workers=None, result=None, persist=None, vertices=None,
-                     edges=None, configuration=None):
-        return self.withStrategies(VertexProgramStrategy(graph_computer, workers, result, persist, vertices,
-                                   edges, configuration))
-<% sourceSpawnMethods.each { method -> %>
-    def <%= method %>(self, *args):
-        traversal = self.get_graph_traversal()
-        traversal.bytecode.add_step("<%= toJava.call(method) %>", *args)
-        return traversal
-<% } %>
-
-class GraphTraversal(Traversal):
-    def __init__(self, graph, traversal_strategies, bytecode):
-        super(GraphTraversal, self).__init__(graph, traversal_strategies, bytecode)
-
-    def __getitem__(self, index):
-        if isinstance(index, int):
-            return self.range(long(index), long(index + 1))
-        elif isinstance(index, slice):
-            low = long(0) if index.start is None else long(index.start)
-            high = long(sys.maxsize) if index.stop is None else long(index.stop)
-            if low == long(0):
-                return self.limit(high)
-            else:
-                return self.range(low,high)
-        else:
-            raise TypeError("Index must be int or slice")
-
-    def __getattr__(self, key):
-        if key.startswith('__'):
-            raise AttributeError(
-                'Python magic methods or keys starting with double underscore cannot be used for Gremlin sugar - prefer values(' + key + ')')
-        return self.values(key)
-
-    def clone(self):
-        return GraphTraversal(self.graph, self.traversal_strategies, copy.deepcopy(self.bytecode))
-<% graphStepMethods.each { method -> %>
-    def <%= method %>(self, *args):
-        self.bytecode.add_step("<%= toJava.call(method) %>", *args)
-        return self
-<% } %>
-    # Deprecated - prefer the underscore suffixed versions e.g filter_()
-
-    def filter(self, *args):
-        self.bytecode.add_step("filter", *args)
-        return self
-
-    def id(self, *args):
-        self.bytecode.add_step("id", *args)
-        return self
-
-    def max(self, *args):
-        self.bytecode.add_step("max", *args)
-        return self
-
-    def min(self, *args):
-        self.bytecode.add_step("min", *args)
-        return self
-
-    def range(self, *args):
-        self.bytecode.add_step("range", *args)
-        return self
-
-    def sum(self, *args):
-        self.bytecode.add_step("sum", *args)
-        return self
-
-class MagicType(type):
-
-    def __getattr__(cls, k):
-        if k.startswith('__'):
-            raise AttributeError(
-                'Python magic methods or keys starting with double underscore cannot be used for Gremlin sugar - prefer values(' + k + ')')
-        return __.values(k)
-
-class __(object):
-    __metaclass__ = MagicType
-    graph_traversal = GraphTraversal
-
-    @classmethod
-    def start(cls):
-        return GraphTraversal(None, None, Bytecode())
-
-    @classmethod
-    def __(cls, *args):
-        return __.inject(*args)
-<% anonStepMethods.each{ method -> %>
-    @classmethod
-    def <%= method %>(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).<%= method %>(*args)
-<% } %>
-    # Deprecated - prefer the underscore suffixed versions e.g filter_()
-
-    @classmethod
-    def filter(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).filter_(*args)
-
-    @classmethod
-    def id(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).id_(*args)
-
-    @classmethod
-    def max(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).max_(*args)
-
-    @classmethod
-    def min(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).min_(*args)
-
-    @classmethod
-    def range(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).range_(*args)
-
-    @classmethod
-    def sum(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).sum_(*args)
-
-<% anonStepMethods.each{ method -> %>
-def <%= method %>(*args):
-    return __.<%= method %>(*args)
-
-<% } %>
-# Deprecated - prefer the underscore suffixed versions e.g filter_()
-
-def filter(*args):
-    return __.filter_(*args)
-
-
-def id(*args):
-    return __.id_(*args)
-
-
-def max(*args):
-    return __.max_(*args)
-
-
-def min(*args):
-    return __.min_(*args)
-
-
-def range(*args):
-    return __.range_(*args)
-
-
-def sum(*args):
-    return __.sum_(*args)
-
-
-<% anonStepMethods.each{ method -> %>statics.add_static('<%= method %>', <%= method %>)
-
-<% } %>
-# Deprecated - prefer the underscore suffixed versions e.g filter_()
-
-statics.add_static('filter', filter)
-statics.add_static('id', id)
-statics.add_static('max', max)
-statics.add_static('min', min)
-statics.add_static('range', range)
-statics.add_static('sum', sum)
diff --git a/gremlin-python/glv/TraversalSource.template b/gremlin-python/glv/TraversalSource.template
deleted file mode 100644
index 3b7ee72..0000000
--- a/gremlin-python/glv/TraversalSource.template
+++ /dev/null
@@ -1,434 +0,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.
-#
-
-import copy
-from aenum import Enum
-from .. import statics
-from ..statics import long
-
-class Traversal(object):
-    def __init__(self, graph, traversal_strategies, bytecode):
-        self.graph = graph
-        self.traversal_strategies = traversal_strategies
-        self.bytecode = bytecode
-        self.side_effects = TraversalSideEffects()
-        self.traversers = None
-        self.last_traverser = None
-
-    def __repr__(self):
-        return str(self.bytecode)
-
-    def __eq__(self, other):
-        if isinstance(other, self.__class__):
-            return self.bytecode == other.bytecode
-        else:
-            return False
-
-    def __iter__(self):
-        return self
-
-    def __next__(self):
-        if self.traversers is None:
-            self.traversal_strategies.apply_strategies(self)
-        if self.last_traverser is None:
-            self.last_traverser = next(self.traversers)
-        object = self.last_traverser.object
-        self.last_traverser.bulk = self.last_traverser.bulk - 1
-        if self.last_traverser.bulk <= 0:
-            self.last_traverser = None
-        return object
-
-    def toList(self):
-        return list(iter(self))
-
-    def toSet(self):
-        return set(iter(self))
-
-    def iterate(self):
-        self.bytecode.add_step("none")
-        while True:
-            try: self.nextTraverser()
-            except StopIteration: return self
-
-    def nextTraverser(self):
-        if self.traversers is None:
-            self.traversal_strategies.apply_strategies(self)
-        if self.last_traverser is None:
-            return next(self.traversers)
-        else:
-            temp = self.last_traverser
-            self.last_traverser = None
-            return temp
-
-    def hasNext(self):
-        if self.traversers is None:
-            self.traversal_strategies.apply_strategies(self)
-        if self.last_traverser is None:
-            try: self.last_traverser = next(self.traversers)
-            except StopIteration: return False
-        return not(self.last_traverser is None) and self.last_traverser.bulk > 0
-
-    def next(self, amount=None):
-        if amount is None:
-            return self.__next__()
-        else:
-            count = 0
-            tempList = []
-            while count < amount:
-                count = count + 1
-                try: temp = self.__next__()
-                except StopIteration: return tempList
-                tempList.append(temp)
-            return tempList
-
-    def promise(self, cb=None):
-        self.traversal_strategies.apply_async_strategies(self)
-        future_traversal = self.remote_results
-        future = type(future_traversal)()
-        def process(f):
-            try:
-                traversal = f.result()
-            except Exception as e:
-                future.set_exception(e)
-            else:
-                self.traversers = iter(traversal.traversers)
-                self.side_effects = traversal.side_effects
-                if cb:
-                    try:
-                        result = cb(self)
-                    except Exception as e:
-                        future.set_exception(e)
-                    else:
-                        future.set_result(result)
-                else:
-                    future.set_result(self)
-        future_traversal.add_done_callback(process)
-        return future
-
-<% enums.each { e -> %>
-<%= e.getSimpleName() %> = Enum('<%= e.getSimpleName() %>', ' <%= e.getEnumConstants().sort{a, b -> a.name() <=> b.name()}.collect{v -> toPython.call(v.name())}.join(" ") %>')
-<% e.getEnumConstants().each {v -> %>
-statics.add_static('<%= toPython.call(v.name()) %>', <%= v.getDeclaringClass().getSimpleName() %>.<%= toPython.call(v.name()) %>)<% } %>
-<% } %>
-
-T = Enum('T', ' id id_ key label value')
-
-statics.add_static('id', T.id)
-statics.add_static('label', T.label)
-statics.add_static('id_', T.id_)
-statics.add_static('key', T.key)
-statics.add_static('value', T.value)
-
-
-Operator = Enum('Operator', ' addAll and_ assign div max max_ min min_ minus mult or_ sum sum_ sumLong')
-
-statics.add_static('sum_', Operator.sum_)
-statics.add_static('sum', Operator.sum_)
-statics.add_static('minus', Operator.minus)
-statics.add_static('mult', Operator.mult)
-statics.add_static('div', Operator.div)
-statics.add_static('min', Operator.min_)
-statics.add_static('min_', Operator.min_)
-statics.add_static('max_', Operator.max_)
-statics.add_static('assign', Operator.assign)
-statics.add_static('and_', Operator.and_)
-statics.add_static('or_', Operator.or_)
-statics.add_static('addAll', Operator.addAll)
-statics.add_static('sumLong', Operator.sumLong)
-
-
-class P(object):
-    def __init__(self, operator, value, other=None):
-        self.operator = operator
-        self.value = value
-        self.other = other
-<% pmethods.findAll{!(it in ["within","without"])}.each { method -> %>
-    @staticmethod
-    def <%= method %>(*args):
-        return P("<%= toJava.call(method) %>", *args)
-<% } %>
-    @staticmethod
-    def within(*args):
-        if len(args) == 1 and type(args[0]) == list:
-            return P("within", args[0])
-        else:
-            return P("within", list(args))
-        
-    @staticmethod
-    def without(*args):
-        if len(args) == 1 and type(args[0]) == list:
-            return P("without", args[0])
-        else:
-            return P("without", list(args))
-
-    def and_(self, arg):
-        return P("and", self, arg)
-
-    def or_(self, arg):
-        return P("or", self, arg)
-
-    def __eq__(self, other):
-        return isinstance(other, self.__class__) and self.operator == other.operator and self.value == other.value and self.other == other.other
-
-    def __repr__(self):
-        return self.operator + "(" + str(self.value) + ")" if self.other is None else self.operator + "(" + str(self.value) + "," + str(self.other) + ")"
-
-<% pmethods.findAll{!it.equals("clone")}.each { method -> %>
-def <%= method %>(*args):
-    return P.<%= method %>(*args)
-
-<% } %>
-<% pmethods.findAll{!it.equals("clone")}.each { method -> %>statics.add_static('<%= method %>', <%= method %>)
-
-<% } %>
-class TextP(P):
-    def __init__(self, operator, value, other=None):
-        P.__init__(self, operator, value, other)
-<% tpmethods.each { method -> %>
-    @staticmethod
-    def <%= method %>(*args):
-        return TextP("<%= toJava.call(method) %>", *args)
-<% } %>
-    def __eq__(self, other):
-        return isinstance(other, self.__class__) and self.operator == other.operator and self.value == other.value and self.other == other.other
-
-    def __repr__(self):
-        return self.operator + "(" + str(self.value) + ")" if self.other is None else self.operator + "(" + str(self.value) + "," + str(self.other) + ")"
-
-<% tpmethods.findAll{!it.equals("clone")}.each { method -> %>
-def <%= method %>(*args):
-    return TextP.<%= method %>(*args)
-
-<% } %>
-<% tpmethods.findAll{!it.equals("clone")}.each { method -> %>statics.add_static('<%= method %>', <%= method %>)
-
-<% } %>
-<% tokens.each { k,v -> %>
-
-'''
-<%= k %>
-'''
-
-
-class <%= k %>(object):
-<% v.each {a,b -> %>
-    <%= a %> = "<%= b %>"
-<% }} %>
-
-'''
-TRAVERSER
-'''
-
-
-class Traverser(object):
-    def __init__(self, object, bulk=None):
-        if bulk is None:
-            bulk = long(1)
-        self.object = object
-        self.bulk = bulk
-
-    def __repr__(self):
-        return str(self.object)
-
-    def __eq__(self, other):
-        return isinstance(other, self.__class__) and self.object == other.object
-
-
-'''
-TRAVERSAL SIDE-EFFECTS
-'''
-
-
-class TraversalSideEffects(object):
-    def keys(self):
-        return set()
-
-    def get(self, key):
-        raise KeyError(key)
-
-    def __getitem__(self, key):
-        return self.get(key)
-
-    def __repr__(self):
-        return "sideEffects[size:" + str(len(self.keys())) + "]"
-
-
-'''
-TRAVERSAL STRATEGIES
-'''
-
-
-class TraversalStrategies(object):
-    global_cache = {}
-
-    def __init__(self, traversal_strategies=None):
-        self.traversal_strategies = \
-            traversal_strategies.traversal_strategies if traversal_strategies is not None else []
-
-    def add_strategies(self, traversal_strategies):
-        self.traversal_strategies = self.traversal_strategies + traversal_strategies
-
-    def apply_strategies(self, traversal):
-        for traversal_strategy in self.traversal_strategies:
-            traversal_strategy.apply(traversal)
-
-    def apply_async_strategies(self, traversal):
-        for traversal_strategy in self.traversal_strategies:
-            traversal_strategy.apply_async(traversal)
-
-    def __repr__(self):
-        return str(self.traversal_strategies)
-
-
-class TraversalStrategy(object):
-    def __init__(self, strategy_name=None, configuration=None, fqcn=None):
-        self.fqcn = fqcn
-        self.strategy_name = type(self).__name__ if strategy_name is None else strategy_name
-        self.configuration = {} if configuration is None else configuration
-
-    def apply(self, traversal):
-        return
-
-    def apply_async(self, traversal):
-        return
-
-    def __eq__(self, other):
-        return isinstance(other, self.__class__)
-
-    def __hash__(self):
-        return hash(self.strategy_name)
-
-    def __repr__(self):
-        return self.strategy_name
-
-
-'''
-BYTECODE
-'''
-
-
-class Bytecode(object):
-    def __init__(self, bytecode=None):
-        self.source_instructions = []
-        self.step_instructions = []
-        self.bindings = {}
-        if bytecode is not None:
-            self.source_instructions = list(bytecode.source_instructions)
-            self.step_instructions = list(bytecode.step_instructions)
-
-    def add_source(self, source_name, *args):
-        instruction = [source_name]
-        for arg in args:
-            instruction.append(self.__convertArgument(arg))
-        self.source_instructions.append(instruction)
-
-    def add_step(self, step_name, *args):
-        instruction = [step_name]
-        for arg in args:
-            instruction.append(self.__convertArgument(arg))
-        self.step_instructions.append(instruction)
-
-    def __eq__(self, other):
-        if isinstance(other, self.__class__):
-            return self.source_instructions == other.source_instructions and self.step_instructions == other.step_instructions
-        else:
-            return False
-
-    def __copy__(self):
-        bb = Bytecode()
-        bb.source_instructions = self.source_instructions
-        bb.step_instructions = self.step_instructions
-        bb.bindings = self.bindings
-        return bb
-
-    def __deepcopy__(self, memo={}):
-        bb = Bytecode()
-        bb.source_instructions = copy.deepcopy(self.source_instructions, memo)
-        bb.step_instructions = copy.deepcopy(self.step_instructions, memo)
-        bb.bindings = copy.deepcopy(self.bindings, memo)
-        return bb
-
-    def __convertArgument(self,arg):
-        if isinstance(arg, Traversal):
-            self.bindings.update(arg.bytecode.bindings)
-            return arg.bytecode
-        elif isinstance(arg, dict):
-            newDict = {}
-            for key in arg:
-                newDict[self.__convertArgument(key)] = self.__convertArgument(arg[key])
-            return newDict
-        elif isinstance(arg, list):
-            newList = []
-            for item in arg:
-                newList.append(self.__convertArgument(item))
-            return newList
-        elif isinstance(arg, set):
-            newSet = set()
-            for item in arg:
-                newSet.add(self.__convertArgument(item))
-            return newSet
-        elif isinstance(arg, Binding):
-            self.bindings[arg.key] = arg.value
-            return Binding(arg.key, self.__convertArgument(arg.value))
-        else:
-            return arg
-
-    def __repr__(self):
-        return (str(self.source_instructions) if len(self.source_instructions) > 0 else "") + \\
-               (str(self.step_instructions) if len(self.step_instructions) > 0 else "")
-
-
-'''
-BINDINGS
-'''
-
-
-class Bindings(object):
-
-    @staticmethod
-    def of(key, value):
-        if not isinstance(key, str):
-            raise TypeError("Key must be str")
-        return Binding(key, value)
-
-
-class Binding(object):
-    def __init__(self, key, value):
-        self.key = key
-        self.value = value
-
-    def __eq__(self, other):
-        return isinstance(other, self.__class__) and self.key == other.key and self.value == other.value
-
-    def __hash__(self):
-        return hash(self.key) + hash(self.value)
-
-    def __repr__(self):
-        return "binding[" + self.key + "=" + str(self.value) + "]"
-
-
-'''
-WITH OPTIONS
-'''
-
-
-class WithOptions(object):
-<% withOptions.each { %>
-    <%= it.name %> = <%= it.value %>
-<% } %>
diff --git a/gremlin-python/glv/generate.groovy b/gremlin-python/glv/generate.groovy
deleted file mode 100644
index 5856e81..0000000
--- a/gremlin-python/glv/generate.groovy
+++ /dev/null
@@ -1,131 +0,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.
- */
-
-import org.apache.tinkerpop.gremlin.jsr223.CoreImports
-import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.ConnectedComponent
-import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.PageRank
-import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.PeerPressure
-import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.ShortestPath
-import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource
-import org.apache.tinkerpop.gremlin.process.traversal.P
-import org.apache.tinkerpop.gremlin.process.traversal.TextP
-import org.apache.tinkerpop.gremlin.process.traversal.IO
-import org.apache.tinkerpop.gremlin.process.traversal.Operator
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.WithOptions
-import org.apache.tinkerpop.gremlin.structure.T
-import java.lang.reflect.Modifier
-
-// this is a bit of a copy of what's in SymbolHelper - no way around it because this code generation task occurs
-// before the SymbolHelper is available to the plugin.
-def toPythonMap = ["and": "and_",
-                   "all": "all_",
-                   "as": "as_",
-                   "filter": "filter_",
-                   "from": "from_",
-                   "global": "global_",
-                   "id": "id_",
-                   "in": "in_",
-                   "is": "is_",
-                   "list": "list_",
-                   "max": "max_",
-                   "min": "min_",
-                   "not": "not_",
-                   "range": "range_",
-                   "or": "or_",
-                   "set": "set_",
-                   "sum": "sum_",
-                   "with": "with_"]
-
-def gatherTokensFrom = { tokenClasses ->
-    def m = [:]
-    tokenClasses.each { tc -> m << [(tc.simpleName) : tc.getFields().sort{ a, b -> a.name <=> b.name }.collectEntries{ f -> [(f.name) : f.get(null)]}]}
-    return m
-}
-
-def toPythonValue = { type, value ->
-  type == String.class && value != null ? ('"' + value + '"') : value
-}
-
-def toJavaMap = toPythonMap.collectEntries{k,v -> [(v):k]}
-def toPython = { symbol -> toPythonMap.getOrDefault(symbol, symbol) }
-def toJava = { symbol -> toJavaMap.getOrDefault(symbol, symbol) }
-
-// for enums we ignore T and handle it manually because of conflict with T.id which is trickier to deal with
-// in the templating language
-def binding = ["enums": CoreImports.getClassImports()
-        .findAll { Enum.class.isAssignableFrom(it) && !(it in [T, Operator]) }
-        .sort { a, b -> a.getSimpleName() <=> b.getSimpleName() },
-               "pmethods": P.class.getMethods().
-                       findAll { Modifier.isStatic(it.getModifiers()) }.
-                       findAll { P.class.isAssignableFrom(it.returnType) }.
-                       collect { toPython(it.name) }.
-                       unique().
-                       sort { a, b -> a <=> b },
-               "tpmethods": TextP.class.getMethods().
-                       findAll { Modifier.isStatic(it.getModifiers()) }.
-                       findAll { TextP.class.isAssignableFrom(it.returnType) }.
-                       collect { toPython(it.name) }.
-                       unique().
-                       sort { a, b -> a <=> b },
-               "sourceStepMethods": GraphTraversalSource.getMethods(). // SOURCE STEPS
-                       findAll { (GraphTraversalSource.class == it.returnType) }.
-                       findAll {
-                           !it.name.equals("clone") &&
-                                   !it.name.equals(TraversalSource.Symbols.with) &&
-                                   !it.name.equals(TraversalSource.Symbols.withRemote) &&
-                                   !it.name.equals(TraversalSource.Symbols.withComputer)
-                       }.
-                       collect { toPython(it.name) }.
-                       unique().
-                       sort { a, b -> a <=> b },
-               "sourceSpawnMethods": GraphTraversalSource.getMethods(). // SPAWN STEPS
-                       findAll { (GraphTraversal.class == it.returnType) }.
-                       collect { toPython(it.name) }.
-                       unique().
-                       sort { a, b -> a <=> b },
-               "graphStepMethods": GraphTraversal.getMethods().
-                       findAll { GraphTraversal.class == it.returnType }.
-                       findAll { it.name != "clone" && it.name != "iterate" }.
-                       collect { toPython(it.name) }.
-                       unique().
-                       sort { a, b -> a <=> b },
-               "anonStepMethods": __.class.getMethods().
-                       findAll { (GraphTraversal.class == it.returnType) }.
-                       findAll { Modifier.isStatic(it.getModifiers()) }.
-                       findAll { it.name != "__" && it.name != "start" }.
-                       collect { toPython(it.name) }.
-                       unique().
-                       sort { a, b -> a <=> b },
-               "tokens": gatherTokensFrom([IO, ConnectedComponent, ShortestPath, PageRank, PeerPressure]),
-               "toPython": toPython,
-               "toJava": toJava,
-               "withOptions": WithOptions.getDeclaredFields().
-                        collect {["name": it.name, "value": toPythonValue(it.type, it.get(null))]}]
-
-def engine = new groovy.text.GStringTemplateEngine()
-def traversalTemplate = engine.createTemplate(new File("${projectBaseDir}/glv/TraversalSource.template")).make(binding)
-def traversalFile = new File("${projectBaseDir}/src/main/jython/gremlin_python/process/traversal.py")
-traversalFile.newWriter().withWriter{ it << traversalTemplate }
-
-def graphTraversalTemplate = engine.createTemplate(new File("${projectBaseDir}/glv/GraphTraversalSource.template")).make(binding)
-def graphTraversalFile = new File("${projectBaseDir}/src/main/jython/gremlin_python/process/graph_traversal.py")
-graphTraversalFile.newWriter().withWriter{ it << graphTraversalTemplate }
diff --git a/gremlin-python/pom.xml b/gremlin-python/pom.xml
index b2e0d6d..37b8fe3 100644
--- a/gremlin-python/pom.xml
+++ b/gremlin-python/pom.xml
@@ -21,46 +21,10 @@
     <parent>
         <groupId>org.apache.tinkerpop</groupId>
         <artifactId>tinkerpop</artifactId>
-        <version>3.4.12-SNAPSHOT</version>
+        <version>3.5.1-SNAPSHOT</version>
     </parent>
     <artifactId>gremlin-python</artifactId>
     <name>Apache TinkerPop :: Gremlin Python</name>
-    <dependencies>
-        <dependency>
-            <groupId>org.apache.tinkerpop</groupId>
-            <artifactId>gremlin-core</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.python</groupId>
-            <artifactId>jython-standalone</artifactId>
-            <version>2.7.1</version>
-        </dependency>
-        <!-- TESTING -->
-        <dependency>
-            <groupId>org.apache.tinkerpop</groupId>
-            <artifactId>tinkergraph-gremlin</artifactId>
-            <version>${project.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.tinkerpop</groupId>
-            <artifactId>gremlin-test</artifactId>
-            <version>${project.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.tinkerpop</groupId>
-            <artifactId>gremlin-server</artifactId>
-            <version>${project.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-log4j12</artifactId>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
     <properties>
         <!-- provides a way to convert maven.test.skip value to skipTests for use in skipping python tests -->
         <maven.test.skip>false</maven.test.skip>
@@ -70,177 +34,42 @@
     <build>
         <directory>${basedir}/target</directory>
         <finalName>${project.artifactId}-${project.version}</finalName>
-        <resources>
-            <resource>
-                <directory>src/main/resources
-                </directory>
-            </resource>
-        </resources>
-        <testResources>
-            <testResource>
-                <directory>${basedir}/src/test/resources
-                </directory>
-            </testResource>
-        </testResources>
         <plugins>
+            <!--
+            there is no point to building/deploying the jvm stuff - there is no java source really - just poms
+            -->
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-clean-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <goals>
-                            <goal>clean</goal>
-                        </goals>
-                    </execution>
-                </executions>
+                <artifactId>maven-javadoc-plugin</artifactId>
                 <configuration>
-                    <filesets>
-                        <!-- SOURCE DIRECTORIES -->
-                        <fileset>
-                            <directory>${basedir}/src/main/jython/gremlin_python</directory>
-                            <includes>
-                                <include>**/*.pyc</include>
-                                <include>**/*.class</include>
-                            </includes>
-                            <excludes>
-                                <exclude>**/*.py</exclude>
-                            </excludes>
-                            <followSymlinks>false</followSymlinks>
-                        </fileset>
-                        <fileset>
-                            <directory>${basedir}/src/main/jython/gremlin_python/driver</directory>
-                            <includes>
-                                <include>**/*.pyc</include>
-                                <include>**/*.class</include>
-                            </includes>
-                            <excludes>
-                                <exclude>**/*.py</exclude>
-                            </excludes>
-                            <followSymlinks>false</followSymlinks>
-                        </fileset>
-                        <fileset>
-                            <directory>${basedir}/src/main/jython/gremlin_python/process</directory>
-                            <includes>
-                                <include>**/*.pyc</include>
-                                <include>**/*.class</include>
-                            </includes>
-                            <excludes>
-                                <exclude>**/*.py</exclude>
-                            </excludes>
-                            <followSymlinks>false</followSymlinks>
-                        </fileset>
-                        <fileset>
-                            <directory>${basedir}/src/main/jython/gremlin_python/structure</directory>
-                            <includes>
-                                <include>**/*.pyc</include>
-                                <include>**/*.class</include>
-                            </includes>
-                            <excludes>
-                                <exclude>**/*.py</exclude>
-                            </excludes>
-                            <followSymlinks>false</followSymlinks>
-                        </fileset>
-                        <fileset>
-                            <directory>${basedir}/src/main/jython/gremlin_python/structure/io</directory>
-                            <includes>
-                                <include>**/*.pyc</include>
-                                <include>**/*.class</include>
-                            </includes>
-                            <excludes>
-                                <exclude>**/*.py</exclude>
-                            </excludes>
-                            <followSymlinks>false</followSymlinks>
-                        </fileset>
-                        <!-- TEST DIRECTORIES -->
-                        <fileset>
-                            <directory>${basedir}/src/main/jython/tests</directory>
-                            <includes>
-                                <include>**/*.pyc</include>
-                                <include>**/*.class</include>
-                            </includes>
-                            <excludes>
-                                <exclude>**/*.py</exclude>
-                            </excludes>
-                            <followSymlinks>false</followSymlinks>
-                        </fileset>
-                        <fileset>
-                            <directory>${basedir}/src/main/jython/tests/driver</directory>
-                            <includes>
-                                <include>**/*.pyc</include>
-                                <include>**/*.class</include>
-                            </includes>
-                            <excludes>
-                                <exclude>**/*.py</exclude>
-                            </excludes>
-                            <followSymlinks>false</followSymlinks>
-                        </fileset>
-                        <fileset>
-                            <directory>${basedir}/src/main/jython/tests/process</directory>
-                            <includes>
-                                <include>**/*.pyc</include>
-                                <include>**/*.class</include>
-                            </includes>
-                            <excludes>
-                                <exclude>**/*.py</exclude>
-                            </excludes>
-                            <followSymlinks>false</followSymlinks>
-                        </fileset>
-                        <fileset>
-                            <directory>${basedir}/src/main/jython/tests/structure</directory>
-                            <includes>
-                                <include>**/*.pyc</include>
-                                <include>**/*.class</include>
-                            </includes>
-                            <excludes>
-                                <exclude>**/*.py</exclude>
-                            </excludes>
-                            <followSymlinks>false</followSymlinks>
-                        </fileset>
-                        <fileset>
-                            <directory>${basedir}/src/main/jython/tests/structure/io</directory>
-                            <includes>
-                                <include>**/*.pyc</include>
-                                <include>**/*.class</include>
-                            </includes>
-                            <excludes>
-                                <exclude>**/*.py</exclude>
-                            </excludes>
-                            <followSymlinks>false</followSymlinks>
-                        </fileset>
-                    </filesets>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-source-plugin</artifactId>
+                <configuration>
+                    <skipSource>true</skipSource>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-install-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-deploy-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
                 </configuration>
             </plugin>
         </plugins>
     </build>
 
     <profiles>
-        <!-- This default profile works around the issue where the glv-python profile which is expected to run all tests
-             can't override the exclusions defined below. -->
-        <profile>
-            <id>glv-python-standard</id>
-            <activation>
-                <activeByDefault>true</activeByDefault>
-            </activation>
-            <build>
-                <plugins>
-                    <!-- excludes python related tests that require python itself installed on the system - run with the
-                         python profile if glVPython is present -->
-                    <plugin>
-                        <groupId>org.apache.maven.plugins</groupId>
-                        <artifactId>maven-surefire-plugin</artifactId>
-                        <configuration>
-                            <systemPropertyVariables>
-                                <python.home>${project.build.outputDirectory}</python.home>
-                            </systemPropertyVariables>
-                            <excludes>
-                                <exclude>**/jsr223/Python*Test.java</exclude>
-                                <exclude>**/graphson/GraphSON*Test.java</exclude>
-                            </excludes>
-                        </configuration>
-                    </plugin>
-                </plugins>
-            </build>
-        </profile>
         <!-- activates the building of python components and requires that python be installed on the system -->
         <profile>
             <id>glv-python</id>
@@ -251,18 +80,7 @@
                 </file>
             </activation>
             <build>
-
-                <!-- don't exclude any tests as python is assumed to be installed on this system -->
                 <plugins>
-                    <plugin>
-                        <groupId>org.apache.maven.plugins</groupId>
-                        <artifactId>maven-surefire-plugin</artifactId>
-                        <configuration>
-                            <systemPropertyVariables>
-                                <python.home>${project.build.outputDirectory}</python.home>
-                            </systemPropertyVariables>
-                        </configuration>
-                    </plugin>
                     <!-- need to create python-reports directory at this point or else pytest can't write the report to it -->
                     <plugin>
                         <groupId>org.apache.maven.plugins</groupId>
@@ -281,7 +99,7 @@
                                     </target>
                                 </configuration>
                             </execution>
-                            <!-- copy files in jython directory to target/py and run virtual env to sandbox python.
+                            <!-- copy files in python directory to target/py and run virtual env to sandbox python.
                                  there is no need to "activate" the virtualenv because all calls to python occur
                                  directly from bin/ -->
                             <execution>
@@ -293,57 +111,35 @@
                                 <configuration>
                                     <tasks>
                                         <!-- seems like we need a few different copies of the same source. all the
-                                             different python/jython stuff doesn't seem to want to share. we use
-                                             /python for basic tests and stuff, /jython for jython compilation with
-                                             the jython plugin, /python-packaged for distribution tasks. some of the
-                                             problem seems to stem from the python lifecycle not binding perfectly well
-                                             to the maven lifecycle (integration tests seems to cause troubles
-                                             specifically). note that the commands to install wheel are largely for
-                                             safety in case someone is using an older version of virtualenv (which
-                                             doesn't install wheel by default) -->
+                                             different python stuff doesn't seem to want to share. we use
+                                             /python3 for basic tests and stuff and /python-packaged for distribution
+                                             tasks. some of the problem seems to stem from the python lifecycle not
+                                             binding perfectly well to the maven lifecycle (integration tests seems to
+                                             cause troubles specifically). note that the commands to install wheel are
+                                             largely for safety in case someone is using an older version of virtualenv
+                                             (which doesn't install wheel by default) -->
                                         <copy todir="${project.build.directory}/python3">
-                                            <fileset dir="src/main/jython"/>
+                                            <fileset dir="src/main/python"/>
                                         </copy>
-                                        <copy todir="${project.build.directory}/python2">
-                                            <fileset dir="src/main/jython"/>
-                                        </copy>
-                                        <copy todir="${project.build.directory}/python-packaged">
-                                            <fileset dir="src/main/jython"/>
-                                        </copy>
-                                        <!-- print versions of python and virtualenv -->
-                                        <exec dir="${project.build.directory}/python2" executable="python2"
+                                        <exec dir="${project.build.directory}/python3" executable="python3"
                                               failonerror="true">
                                             <arg line="--version"/>
                                         </exec>
-                                        <exec dir="${project.build.directory}/python2" executable="python3"
+                                        <exec dir="${project.build.directory}/python3" executable="virtualenv"
                                               failonerror="true">
                                             <arg line="--version"/>
                                         </exec>
-                                        <exec dir="${project.build.directory}/python2" executable="virtualenv"
-                                              failonerror="true">
-                                            <arg line="--version"/>
-                                        </exec>
-                                        <exec dir="${project.build.directory}/python2" executable="virtualenv"
-                                              failonerror="true">
-                                            <arg line="--python=python2 env"/>
-                                        </exec>
-                                        <!-- pip 20 doesn't work with python 2 it seems -->
-                                        <exec dir="${project.build.directory}/python2" executable="env/bin/python"
-                                              failonerror="true">
-                                            <arg line="-m pip install pip&gt;=19.3.1,&lt;20.0.0"/>
-                                        </exec>
-                                        <exec dir="${project.build.directory}/python2" executable="env/bin/pip"
-                                              failonerror="true">
-                                            <arg line="install wheel radish-bdd PyHamcrest aenum isodate"/>
-                                        </exec>
                                         <exec dir="${project.build.directory}/python3" executable="virtualenv"
                                               failonerror="true">
                                             <arg line="--python=python3 env"/>
                                         </exec>
                                         <exec dir="${project.build.directory}/python3" executable="env/bin/pip"
                                               failonerror="true">
-                                            <arg line="install wheel radish-bdd PyHamcrest aenum isodate"/>
+                                            <arg line="install wheel radish-bdd PyHamcrest aenum isodate kerberos six"/>
                                         </exec>
+                                        <copy todir="${project.build.directory}/python-packaged">
+                                            <fileset dir="src/main/python"/>
+                                        </copy>
                                         <exec dir="${project.build.directory}/python-packaged" executable="virtualenv"
                                               failonerror="true">
                                             <arg line="--python=python3 env"/>
@@ -356,23 +152,6 @@
                                 </configuration>
                             </execution>
                             <execution>
-                                <id>native-python2-build</id>
-                                <phase>compile</phase>
-                                <goals>
-                                    <goal>run</goal>
-                                </goals>
-                                <configuration>
-                                    <target>
-                                        <exec executable="env/bin/python" dir="${project.build.directory}/python2"
-                                              failonerror="true">
-                                            <env key="PYTHONPATH" value=""/>
-                                            <!-- oddly the "build-lib" needs to be in place or else docs won't generate -->
-                                            <arg line="setup.py build --build-lib ${project.build.outputDirectory}/Lib"/>
-                                        </exec>
-                                    </target>
-                                </configuration>
-                            </execution>
-                            <execution>
                                 <id>native-python3-build</id>
                                 <phase>compile</phase>
                                 <goals>
@@ -418,48 +197,6 @@
                             test phase doesn't have a pre/post event like integration-test does.
                             -->
                             <execution>
-                                <id>native-python2-test</id>
-                                <phase>integration-test</phase>
-                                <goals>
-                                    <goal>run</goal>
-                                </goals>
-                                <configuration>
-                                    <skip>${skipTests}</skip>
-                                    <target>
-                                        <!-- setup.py seems to have troubles with the recently published zipp 1.0.0 -->
-                                        <exec dir="${project.build.directory}/python2" executable="env/bin/python"
-                                              failonerror="true">
-                                            <arg line="-m pip install zipp&gt;=0.5.0,&lt;1.0.0"/>
-                                        </exec>
-                                        <exec executable="env/bin/python" dir="${project.build.directory}/python2"
-                                              failonerror="true">
-                                            <env key="PYTHONPATH" value=""/>
-                                            <arg line="setup.py test"/>
-                                        </exec>
-                                        <!-- radish seems to like all dependencies in place -->
-                                        <exec executable="env/bin/python" dir="${project.build.directory}/python2"
-                                              failonerror="true">
-                                            <env key="PYTHONPATH" value=""/>
-                                            <arg line="setup.py install"/>
-                                        </exec>
-                                        <!-- run for graphson 3.0 -->
-                                        <exec executable="env/bin/radish" dir="${project.build.directory}/python2"
-                                              failonerror="true">
-                                            <env key="PYTHONPATH" value=""/>
-                                            <env key="PYTHONIOENCODING" value="utf-8:surrogateescape"/>
-                                            <arg line="-f dots -e -t -b ${project.build.directory}/python2/radish ${project.basedir}/../gremlin-test/features/ --user-data=&quot;serializer=application/vnd.gremlin-v3.0+json&quot;"/> <!-- -no-line-jump -->
-                                        </exec>
-                                        <!-- run for graphbinary 1.0 -->
-                                        <exec executable="env/bin/radish" dir="${project.build.directory}/python2"
-                                              failonerror="true">
-                                            <env key="PYTHONPATH" value=""/>
-                                            <env key="PYTHONIOENCODING" value="utf-8:surrogateescape"/>
-                                            <arg line="-f dots -e -t -b ${project.build.directory}/python2/radish ${project.basedir}/../gremlin-test/features/ --user-data=&quot;serializer=application/vnd.graphbinary-v1.0&quot;"/> <!-- -no-line-jump -->
-                                        </exec>
-                                    </target>
-                                </configuration>
-                            </execution>
-                            <execution>
                                 <id>native-python3-test</id>
                                 <phase>integration-test</phase>
                                 <goals>
@@ -471,8 +208,30 @@
                                         <exec executable="env/bin/python" dir="${project.build.directory}/python3"
                                               failonerror="true">
                                             <env key="PYTHONPATH" value=""/>
+                                            <env key="KRB5_CONFIG" value="${project.build.directory}/kdc/krb5.conf"/>
+                                            <env key="KRB5CCNAME" value="${project.build.directory}/kdc/test-tkt.cc"/>
                                             <arg line="setup.py test"/>
                                         </exec>
+                                        <!-- radish seems to like all dependencies in place -->
+                                        <exec executable="env/bin/python" dir="${project.build.directory}/python3"
+                                              failonerror="true">
+                                            <env key="PYTHONPATH" value=""/>
+                                            <arg line="setup.py install"/>
+                                        </exec>
+                                        <!-- run for graphson 3.0 -->
+                                        <exec executable="env/bin/radish" dir="${project.build.directory}/python3"
+                                              failonerror="true">
+                                            <env key="PYTHONPATH" value=""/>
+                                            <env key="PYTHONIOENCODING" value="utf-8:surrogateescape"/>
+                                            <arg line="-f dots -e -t -b ${project.build.directory}/python3/radish ${project.basedir}/../gremlin-test/features/ --user-data=&quot;serializer=application/vnd.gremlin-v3.0+json&quot;"/> <!-- -no-line-jump -->
+                                        </exec>
+                                        <!-- run for graphbinary 1.0 -->
+                                        <exec executable="env/bin/radish" dir="${project.build.directory}/python3"
+                                              failonerror="true">
+                                            <env key="PYTHONPATH" value=""/>
+                                            <env key="PYTHONIOENCODING" value="utf-8:surrogateescape"/>
+                                            <arg line="-f dots -e -t -b ${project.build.directory}/python3/radish ${project.basedir}/../gremlin-test/features/ --user-data=&quot;serializer=application/vnd.graphbinary-v1.0&quot;"/> <!-- -no-line-jump -->
+                                        </exec>
                                     </target>
                                 </configuration>
                             </execution>
@@ -483,6 +242,16 @@
                         <artifactId>gmavenplus-plugin</artifactId>
                         <dependencies>
                             <dependency>
+                                <groupId>org.apache.tinkerpop</groupId>
+                                <artifactId>gremlin-server</artifactId>
+                                <version>${project.version}</version>
+                            </dependency>
+                            <dependency>
+                                <groupId>org.apache.tinkerpop</groupId>
+                                <artifactId>gremlin-test</artifactId>
+                                <version>${project.version}</version>
+                            </dependency>
+                            <dependency>
                                 <groupId>org.codehaus.groovy</groupId>
                                 <artifactId>groovy-all</artifactId>
                                 <version>${groovy.version}</version>
@@ -498,7 +267,7 @@
                         </dependencies>
                         <executions>
                             <execution>
-                                <id>generate-dsl</id>
+                                <id>generate-radish-support</id>
                                 <phase>generate-sources</phase>
                                 <goals>
                                     <goal>execute</goal>
@@ -507,11 +276,11 @@
                                     <properties>
                                         <property>
                                             <name>projectBaseDir</name>
-                                            <value>${project.basedir}</value>
+                                            <value>${project.basedir}/../</value>
                                         </property>
                                     </properties>
                                     <scripts>
-                                        <script>${project.basedir}/glv/generate.groovy</script>
+                                        <script>${project.basedir}/build/generate.groovy</script>
                                     </scripts>
                                 </configuration>
                             </execution>
@@ -528,10 +297,6 @@
                                             <value>${skipTests}</value>
                                         </property>
                                         <property>
-                                            <name>python</name>
-                                            <value>true</value>
-                                        </property>
-                                        <property>
                                             <name>gremlinServerDir</name>
                                             <value>${gremlin.server.dir}</value>
                                         </property>
@@ -596,19 +361,6 @@
             </activation>
             <build>
                 <plugins>
-                    <!--
-                    pypi doesn't have a staging area like sonatype so the deploy to pypi is done out of the normal
-                    release band. it is performed after successful VOTE in which case, the maven artifacts should
-                    not be deployed again - hence the plugin is disabled. deployment to pypi uses the antrun plugin
-                    below with twine so disabling the plugin has no effect on the pypi deployment.
-                    -->
-                    <plugin>
-                        <groupId>org.apache.maven.plugins</groupId>
-                        <artifactId>maven-deploy-plugin</artifactId>
-                        <configuration>
-                            <skip>true</skip>
-                        </configuration>
-                    </plugin>
                     <plugin>
                         <groupId>org.apache.maven.plugins</groupId>
                         <artifactId>maven-antrun-plugin</artifactId>
diff --git a/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/GremlinJythonScriptEngine.java b/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/GremlinJythonScriptEngine.java
deleted file mode 100644
index 86473c4..0000000
--- a/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/GremlinJythonScriptEngine.java
+++ /dev/null
@@ -1,250 +0,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.
- */
-
-package org.apache.tinkerpop.gremlin.python.jsr223;
-
-import org.apache.tinkerpop.gremlin.jsr223.CoreGremlinPlugin;
-import org.apache.tinkerpop.gremlin.jsr223.CoreImports;
-import org.apache.tinkerpop.gremlin.jsr223.Customizer;
-import org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngine;
-import org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngineFactory;
-import org.apache.tinkerpop.gremlin.jsr223.ImportCustomizer;
-import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
-import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
-import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
-import org.python.jsr223.PyScriptEngine;
-import org.python.jsr223.PyScriptEngineFactory;
-
-import javax.script.Bindings;
-import javax.script.ScriptContext;
-import javax.script.ScriptException;
-import javax.script.SimpleBindings;
-import java.io.Reader;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * @deprecated As of release 3.3.10, not replaced - see TINKERPOP-2317
- *
- * @author Marko A. Rodriguez (http://markorodriguez.com)
- * @author Stephen Mallette (http://stephen.genoprime.com)
- */
-@Deprecated
-public class GremlinJythonScriptEngine implements GremlinScriptEngine {
-
-    private final PyScriptEngine pyScriptEngine;
-
-    public GremlinJythonScriptEngine(final Customizer... customizers) {
-        this.pyScriptEngine = (PyScriptEngine) new PyScriptEngineFactory().getScriptEngine();
-        final List<Customizer> listOfCustomizers = new ArrayList<>(Arrays.asList(customizers));
-
-        // always need this plugin for a scriptengine to be "Gremlin-enabled"
-        CoreGremlinPlugin.instance().getCustomizers("gremlin-jython").ifPresent(c -> listOfCustomizers.addAll(Arrays.asList(c)));
-
-        final List<ImportCustomizer> importCustomizers = listOfCustomizers.stream()
-                .filter(p -> p instanceof ImportCustomizer)
-                .map(p -> (ImportCustomizer) p)
-                .collect(Collectors.toList());
-
-        try {
-            for (ImportCustomizer ic : importCustomizers) {
-                for (Class<?> c : ic.getClassImports()) {
-                    if (null == c.getDeclaringClass())
-                        this.pyScriptEngine.eval("from " + c.getPackage().getName() + " import " + c.getSimpleName());
-                    else
-                        this.pyScriptEngine.eval("from " + c.getPackage().getName() + "." + c.getDeclaringClass().getSimpleName() + " import " + c.getSimpleName());
-                }
-
-                for (Method m : ic.getMethodImports()) {
-                    this.pyScriptEngine.eval(SymbolHelper.toPython(m.getName()) + " = " + m.getDeclaringClass().getSimpleName() + "." + m.getName());
-                }
-
-                // enums need to import after methods for some reason or else label comes in as a PyReflectedFunction
-                for (Enum e : ic.getEnumImports()) {
-                    this.pyScriptEngine.eval(SymbolHelper.toPython(e.name()) + " = " + e.getDeclaringClass().getSimpleName() + "." + e.name());
-                }
-            }
-
-            loadSugar();
-
-        } catch (Exception ex) {
-            throw new IllegalStateException(ex);
-        }
-    }
-
-    @Override
-    public Traversal.Admin eval(final Bytecode bytecode, final Bindings bindings, final String traversalSource) throws ScriptException {
-        // these validations occur before merging in bytecode bindings which will override existing ones. need to
-        // extract the named traversalsource prior to that happening so that bytecode bindings can share the same
-        // namespace as global bindings (e.g. traversalsources and graphs).
-        if (traversalSource.equals(HIDDEN_G))
-            throw new IllegalArgumentException("The traversalSource cannot have the name " + HIDDEN_G + " - it is reserved");
-
-        if (!bindings.containsKey(traversalSource))
-            throw new IllegalArgumentException("The bindings available to the ScriptEngine do not contain a traversalSource named: " + traversalSource);
-
-        final Object b = bindings.get(traversalSource);
-        if (!(b instanceof TraversalSource))
-            throw new IllegalArgumentException(traversalSource + " is of type " + b.getClass().getSimpleName() + " and is not an instance of TraversalSource");
-
-        final Bindings inner = new SimpleBindings();
-        inner.putAll(bindings);
-        inner.putAll(bytecode.getBindings());
-        inner.put(HIDDEN_G, b);
-
-        return (Traversal.Admin) this.eval(JythonTranslator.of(HIDDEN_G).translate(bytecode), inner);
-    }
-
-    @Override
-    public Object eval(final String script, final ScriptContext context) throws ScriptException {
-        return this.pyScriptEngine.eval(script, context);
-    }
-
-    @Override
-    public Object eval(final Reader reader, final ScriptContext context) throws ScriptException {
-        return this.pyScriptEngine.eval(reader, context);
-    }
-
-    @Override
-    public Object eval(final String script) throws ScriptException {
-        return this.pyScriptEngine.eval(script);
-    }
-
-    @Override
-    public Object eval(final Reader reader) throws ScriptException {
-        return this.pyScriptEngine.eval(reader);
-    }
-
-    @Override
-    public Object eval(final String script, final Bindings n) throws ScriptException {
-        this.pyScriptEngine.getBindings(ScriptContext.ENGINE_SCOPE).putAll(n); // TODO: groovy and jython act different
-        return this.pyScriptEngine.eval(script);
-    }
-
-    @Override
-    public Object eval(final Reader reader, final Bindings n) throws ScriptException {
-        this.pyScriptEngine.getBindings(ScriptContext.ENGINE_SCOPE).putAll(n); // TODO: groovy and jython act different
-        return this.pyScriptEngine.eval(reader);
-    }
-
-    @Override
-    public void put(final String key, final Object value) {
-        this.pyScriptEngine.put(key, value);
-    }
-
-    @Override
-    public Object get(final String key) {
-        return this.pyScriptEngine.get(key);
-    }
-
-    @Override
-    public Bindings getBindings(final int scope) {
-        return this.pyScriptEngine.getBindings(scope);
-    }
-
-    @Override
-    public void setBindings(final Bindings bindings, final int scope) {
-        this.pyScriptEngine.setBindings(bindings, scope);
-    }
-
-    @Override
-    public Bindings createBindings() {
-        return this.pyScriptEngine.createBindings();
-    }
-
-    @Override
-    public ScriptContext getContext() {
-        return this.pyScriptEngine.getContext();
-    }
-
-    @Override
-    public void setContext(final ScriptContext context) {
-        this.pyScriptEngine.setContext(context);
-    }
-
-    @Override
-    public GremlinScriptEngineFactory getFactory() {
-        return new GremlinJythonScriptEngineFactory();
-    }
-
-    private void loadSugar() throws ScriptException {
-        // add sugar methods
-        this.pyScriptEngine.eval("def getitem_bypass(self, index):\n" +
-                "  if isinstance(index,int):\n    return self.range(index,index+1)\n" +
-                "  elif isinstance(index,slice):\n    return self.range(index.start,index.stop)\n" +
-                "  else:\n    return TypeError('Index must be int or slice')");
-        this.pyScriptEngine.eval(GraphTraversal.class.getSimpleName() + ".__getitem__ = getitem_bypass");
-        this.pyScriptEngine.eval(GraphTraversal.class.getSimpleName() + ".__getattr__ = lambda self, key: self.values(key)\n");
-        this.pyScriptEngine.eval("\n" +
-                "from java.lang import Long\n" +
-                "import org.apache.tinkerpop.gremlin.util.function.Lambda\n" + // todo: remove or remove imported subclass names? (choose)
-                "from org.apache.tinkerpop.gremlin.util.function.Lambda import AbstractLambda\n" +
-                "from org.apache.tinkerpop.gremlin.util.function.Lambda import UnknownArgLambda\n" +
-                "from org.apache.tinkerpop.gremlin.util.function.Lambda import ZeroArgLambda\n" +
-                "from org.apache.tinkerpop.gremlin.util.function.Lambda import OneArgLambda\n" +
-                "from org.apache.tinkerpop.gremlin.util.function.Lambda import TwoArgLambda\n\n" +
-
-                "class JythonUnknownArgLambda(UnknownArgLambda):\n" +
-                "  def __init__(self,func,script='none',lang='gremlin-jython'):\n" +
-                "    UnknownArgLambda.__init__(self, script, lang, -1)\n" +
-                "    self.func = func\n" +
-                "  def __repr__(self):\n" +
-                "    return self.getLambdaScript()\n\n" +
-
-                "class JythonZeroArgLambda(ZeroArgLambda):\n" +
-                "  def __init__(self,func,script='none',lang='gremlin-jython'):\n" +
-                "    ZeroArgLambda.__init__(self, script, lang)\n" +
-                "    self.func = func\n" +
-                "  def __repr__(self):\n" +
-                "    return self.getLambdaScript()\n" +
-                "  def get(self):\n" +
-                "    return self.func()\n\n" +
-
-                "class JythonOneArgLambda(OneArgLambda):\n" +
-                "  def __init__(self,func,script='none',lang='gremlin-jython'):\n" +
-                "    OneArgLambda.__init__(self, script, lang)\n" +
-                "    self.func = func\n" +
-                "  def __repr__(self):\n" +
-                "    return self.getLambdaScript()\n" +
-                "  def test(self,a):\n" +
-                "    return self.func(a)\n" +
-                "  def apply(self,a):\n" +
-                "    return self.func(a)\n" +
-                "  def accept(self,a):\n" +
-                "    self.func(a)\n" +
-                "  def compare(self,a,b):\n" +
-                "    return self.func(a,b)\n\n" +
-
-                "class JythonTwoArgLambda(TwoArgLambda):\n" +
-                "  def __init__(self,func,script='none',lang='gremlin-jython'):\n" +
-                "    TwoArgLambda.__init__(self, script, lang)\n" +
-                "    self.func = func\n" +
-                "  def __repr__(self):\n" +
-                "    return self.getLambdaScript()\n" +
-                "  def apply(self,a,b):\n" +
-                "    return self.func(a,b)\n" +
-                "  def compare(self,a,b):\n" +
-                "    return self.func(a,b)\n"
-        );
-    }
-}
diff --git a/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/GremlinJythonScriptEngineFactory.java b/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/GremlinJythonScriptEngineFactory.java
deleted file mode 100644
index f3cafc1..0000000
--- a/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/GremlinJythonScriptEngineFactory.java
+++ /dev/null
@@ -1,115 +0,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.
- */
-
-package org.apache.tinkerpop.gremlin.python.jsr223;
-
-import org.apache.tinkerpop.gremlin.jsr223.Customizer;
-import org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngine;
-import org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngineFactory;
-import org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngineManager;
-import org.apache.tinkerpop.gremlin.util.Gremlin;
-import org.python.jsr223.PyScriptEngineFactory;
-
-import javax.script.ScriptEngine;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * @deprecated As of release 3.3.10, not replaced - see TINKERPOP-2317
- *
- * @author Marko A. Rodriguez (http://markorodriguez.com)
- */
-@Deprecated
-public class GremlinJythonScriptEngineFactory extends PyScriptEngineFactory implements GremlinScriptEngineFactory {
-
-    private static final String GREMLIN_JYTHON = "gremlin-jython";
-    private static final String GREMLIN_PYTHON = "gremlin-python";
-    private static final String PLAIN = "plain";
-    private static final List<String> EXTENSIONS = Collections.singletonList("py");
-
-    private GremlinScriptEngineManager manager;
-
-    @Override
-    public void setCustomizerManager(final GremlinScriptEngineManager manager) {
-        this.manager = manager;
-    }
-
-    @Override
-    public String getEngineName() {
-        return GREMLIN_JYTHON;
-    }
-
-    @Override
-    public String getEngineVersion() {
-        return Gremlin.version();
-    }
-
-    @Override
-    public List<String> getExtensions() {
-        return EXTENSIONS;
-    }
-
-    @Override
-    public String getLanguageName() {
-        return GREMLIN_JYTHON;
-    }
-
-    @Override
-    public String getLanguageVersion() {
-        return Gremlin.version();
-    }
-
-    @Override
-    public List<String> getMimeTypes() {
-        return Collections.singletonList(PLAIN);
-    }
-
-    @Override
-    public List<String> getNames() {
-        return Arrays.asList(GREMLIN_JYTHON, GREMLIN_PYTHON);
-    }
-
-    @Override
-    public Object getParameter(final String key) {
-        if (key.equals(ScriptEngine.ENGINE)) {
-            return this.getEngineName();
-        } else if (key.equals(ScriptEngine.ENGINE_VERSION)) {
-            return this.getEngineVersion();
-        } else if (key.equals(ScriptEngine.NAME)) {
-            return GREMLIN_JYTHON;
-        } else if (key.equals(ScriptEngine.LANGUAGE)) {
-            return this.getLanguageName();
-        } else if (key.equals(ScriptEngine.LANGUAGE_VERSION)) {
-            return this.getLanguageVersion();
-        } else
-            return super.getParameter(key);
-    }
-
-    @Override
-    public GremlinScriptEngine getScriptEngine() {
-        final Set<Customizer> customizers = new HashSet<>(manager.getCustomizers(GREMLIN_JYTHON));
-        customizers.addAll(manager.getCustomizers(GREMLIN_PYTHON));
-
-        return (customizers.isEmpty()) ? new GremlinJythonScriptEngine() :
-                new GremlinJythonScriptEngine(customizers.toArray(new Customizer[customizers.size()]));
-    }
-}
\ No newline at end of file
diff --git a/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/JythonTranslator.java b/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/JythonTranslator.java
deleted file mode 100644
index 0a77526..0000000
--- a/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/JythonTranslator.java
+++ /dev/null
@@ -1,81 +0,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.
- */
-
-package org.apache.tinkerpop.gremlin.python.jsr223;
-
-import org.apache.commons.configuration.ConfigurationConverter;
-import org.apache.tinkerpop.gremlin.process.traversal.strategy.TraversalStrategyProxy;
-import org.apache.tinkerpop.gremlin.util.function.Lambda;
-
-/**
- * @deprecated As of release 3.3.10, not replaced - see TINKERPOP-2317
- *
- * @author Marko A. Rodriguez (http://markorodriguez.com)
- * @author Stephen Mallette (http://stephen.genoprime.com)
- */
-@Deprecated
-public final class JythonTranslator extends PythonTranslator {
-
-    private JythonTranslator(final String traversalSource, final boolean importStatics) {
-        super(traversalSource, importStatics);
-    }
-
-    public static JythonTranslator of(final String traversalSource) {
-        return new JythonTranslator(traversalSource, false);
-    }
-
-    @Override
-    public String getTargetLanguage() {
-        return "gremlin-jython";
-    }
-
-    @Override
-    protected String convertLambdaToString(final Lambda lambda) {
-        String lambdaString = lambda.getLambdaScript().trim();
-        lambdaString = lambdaString.startsWith("lambda") ?
-                lambdaString :
-                "lambda " + lambdaString;
-        if (0 == lambda.getLambdaArguments())
-            return "JythonZeroArgLambda(" + lambdaString + ")";
-        else if (1 == lambda.getLambdaArguments())
-            return "JythonOneArgLambda(" + lambdaString + ")";
-        else if (2 == lambda.getLambdaArguments())
-            return "JythonTwoArgLambda(" + lambdaString + ")";
-        else
-            return "JythonUnknownArgLambda(" + lambdaString + ")";
-    }
-
-    @Override
-    protected String resolveSymbol(final String methodName) {
-        // since this is Jython we should expect the Gremlin to conform to the java classes to which the engine is
-        // bound - therefore, unlike the python engine which converts java names to python friendly ones, this
-        // jython one can just pass them through.
-        return methodName;
-    }
-
-    @Override
-    protected String resolveTraversalStrategyProxy(final TraversalStrategyProxy proxy) {
-        // since this is jython we don't need a traversal proxy here - we need the actual JVM version of the strategy
-        // since this script will be executed in Jython. 
-        if (proxy.getConfiguration().isEmpty())
-            return proxy.getStrategyClass().getCanonicalName() + ".instance()";
-        else
-            return proxy.getStrategyClass().getCanonicalName() + ".create(org.apache.commons.configuration.MapConfiguration(" + convertToString(ConfigurationConverter.getMap(proxy.getConfiguration())) + "))";
-    }
-}
diff --git a/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonTranslator.java b/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonTranslator.java
deleted file mode 100644
index 2002681..0000000
--- a/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonTranslator.java
+++ /dev/null
@@ -1,266 +0,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.
- */
-
-package org.apache.tinkerpop.gremlin.python.jsr223;
-
-import org.apache.commons.configuration.ConfigurationConverter;
-import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
-import org.apache.tinkerpop.gremlin.process.traversal.Operator;
-import org.apache.tinkerpop.gremlin.process.traversal.P;
-import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
-import org.apache.tinkerpop.gremlin.process.traversal.TextP;
-import org.apache.tinkerpop.gremlin.process.traversal.Translator;
-import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
-import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
-import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
-import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent;
-import org.apache.tinkerpop.gremlin.process.traversal.strategy.TraversalStrategyProxy;
-import org.apache.tinkerpop.gremlin.process.traversal.util.ConnectiveP;
-import org.apache.tinkerpop.gremlin.process.traversal.util.OrP;
-import org.apache.tinkerpop.gremlin.structure.Edge;
-import org.apache.tinkerpop.gremlin.structure.Element;
-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.util.StringFactory;
-import org.apache.tinkerpop.gremlin.util.function.Lambda;
-import org.apache.tinkerpop.gremlin.util.iterator.ArrayIterator;
-import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
-
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-/**
- * @deprecated As of release 3.3.10, moved to gremlin-core at
- * {@link org.apache.tinkerpop.gremlin.process.traversal.translator.PythonTranslator}
- *
- * @author Marko A. Rodriguez (http://markorodriguez.com)
- * @author Stephen Mallette (http://stephen.genoprime.com)
- */
-@Deprecated
-public class PythonTranslator implements Translator.ScriptTranslator {
-
-    private static final Set<String> STEP_NAMES = Stream.of(GraphTraversal.class.getMethods()).filter(method -> Traversal.class.isAssignableFrom(method.getReturnType())).map(Method::getName).collect(Collectors.toSet());
-    private static final Set<String> NO_STATIC = Stream.of(T.values(), Operator.values())
-            .flatMap(arg -> IteratorUtils.stream(new ArrayIterator<>(arg)))
-            .map(arg -> ((Enum) arg).name())
-            .collect(Collectors.toCollection(() -> new HashSet<>(Collections.singleton("not"))));
-
-    private final String traversalSource;
-    private final boolean importStatics;
-
-    PythonTranslator(final String traversalSource, final boolean importStatics) {
-        this.traversalSource = traversalSource;
-        this.importStatics = importStatics;
-    }
-
-    public static PythonTranslator of(final String traversalSource, final boolean importStatics) {
-        return new PythonTranslator(traversalSource, importStatics);
-    }
-
-    public static PythonTranslator of(final String traversalSource) {
-        return new PythonTranslator(traversalSource, false);
-    }
-
-    @Override
-    public String getTraversalSource() {
-        return this.traversalSource;
-    }
-
-    @Override
-    public String translate(final Bytecode bytecode) {
-        return this.internalTranslate(this.traversalSource, bytecode);
-    }
-
-    @Override
-    public String getTargetLanguage() {
-        return "gremlin-python";
-    }
-
-    @Override
-    public String toString() {
-        return StringFactory.translatorString(this);
-    }
-
-    ///////
-
-    private String internalTranslate(final String start, final Bytecode bytecode) {
-        final StringBuilder traversalScript = new StringBuilder(start);
-        for (final Bytecode.Instruction instruction : bytecode.getInstructions()) {
-            final String methodName = instruction.getOperator();
-            final Object[] arguments = instruction.getArguments();
-            if (0 == arguments.length)
-                traversalScript.append(".").append(resolveSymbol(methodName)).append("()");
-            else if (methodName.equals("range") && 2 == arguments.length)
-                if (((Number) arguments[0]).longValue() + 1 == ((Number) arguments[1]).longValue())
-                    traversalScript.append("[").append(arguments[0]).append("]");
-                else
-                    traversalScript.append("[").append(arguments[0]).append(":").append(arguments[1]).append("]");
-            else if (methodName.equals("limit") && 1 == arguments.length)
-                traversalScript.append("[0:").append(arguments[0]).append("]");
-            else if (methodName.equals("values") && 1 == arguments.length && traversalScript.length() > 3 && !STEP_NAMES.contains(arguments[0].toString()))
-                traversalScript.append(".").append(arguments[0]);
-            else {
-                traversalScript.append(".");
-                String temp = resolveSymbol(methodName) + "(";
-
-                // jython has trouble with java varargs...wrapping in collection seems to solve the problem
-                final boolean varargsBeware = instruction.getOperator().equals(TraversalSource.Symbols.withStrategies)
-                            || instruction.getOperator().equals(TraversalSource.Symbols.withoutStrategies);
-                if (varargsBeware) temp = temp + "[";
-
-                for (final Object object : arguments) {
-                    temp = temp + convertToString(object) + ",";
-                }
-                temp = temp.substring(0, temp.length() - 1);
-
-                if (varargsBeware) temp = temp + "]";
-
-                traversalScript.append(temp).append(")");
-            }
-            // clip off __.
-            if (this.importStatics && traversalScript.substring(0, 3).startsWith("__.")
-                    && !NO_STATIC.stream().filter(name -> traversalScript.substring(3).startsWith(resolveSymbol(name))).findAny().isPresent()) {
-                traversalScript.delete(0, 3);
-            }
-        }
-        return traversalScript.toString();
-    }
-
-    protected String convertToString(final Object object) {
-        if (object instanceof Bytecode.Binding)
-            return ((Bytecode.Binding) object).variable();
-        else if (object instanceof Bytecode)
-            return this.internalTranslate("__", (Bytecode) object);
-        else if (object instanceof Traversal)
-            return convertToString(((Traversal) object).asAdmin().getBytecode());
-        else if (object instanceof String)
-            return ((String) object).contains("\"") ? "\"\"\"" + object + "\"\"\"" : "\"" + object + "\"";
-        else if (object instanceof Set) {
-            final Set<String> set = new LinkedHashSet<>(((Set) object).size());
-            for (final Object item : (Set) object) {
-                set.add(convertToString(item));
-            }
-            return "set(" + set.toString() + ")";
-        } else if (object instanceof List) {
-            final List<String> list = new ArrayList<>(((List) object).size());
-            for (final Object item : (List) object) {
-                list.add(convertToString(item));
-            }
-            return list.toString();
-        } else if (object instanceof Map) {
-            final StringBuilder map = new StringBuilder("{");
-            for (final Map.Entry<?, ?> entry : ((Map<?, ?>) object).entrySet()) {
-                map.append(convertToString(entry.getKey())).
-                        append(":").
-                        append(convertToString(entry.getValue())).
-                        append(",");
-            }
-            return map.length() > 1 ? map.substring(0, map.length() - 1) + "}" : map.append("}").toString();
-        } else if (object instanceof Long)
-            return object + "L";
-        else if (object instanceof TraversalStrategyProxy) {
-            return resolveTraversalStrategyProxy((TraversalStrategyProxy) object);
-        } else if (object instanceof TraversalStrategy) {
-            return convertToString(new TraversalStrategyProxy((TraversalStrategy) object));
-        } else if (object instanceof Boolean)
-            return object.equals(Boolean.TRUE) ? "True" : "False";
-        else if (object instanceof Class)
-            return ((Class) object).getCanonicalName();
-        else if (object instanceof VertexProperty.Cardinality)
-            return "Cardinality." + resolveSymbol(object.toString());
-        else if (object instanceof SackFunctions.Barrier)
-            return "Barrier." + resolveSymbol(object.toString());
-        else if (object instanceof TraversalOptionParent.Pick)
-            return "Pick." + resolveSymbol(object.toString());
-        else if (object instanceof Enum)
-            return convertStatic(((Enum) object).getDeclaringClass().getSimpleName() + ".") + resolveSymbol(object.toString());
-        else if (object instanceof P)
-            return convertPToString((P) object, new StringBuilder()).toString();
-        else if (object instanceof Element) {
-            if (object instanceof Vertex) {
-                final Vertex vertex = (Vertex) object;
-                return "Vertex(" + convertToString(vertex.id()) + "," + convertToString(vertex.label()) + ")";
-            } else if (object instanceof Edge) {
-                final Edge edge = (Edge) object;
-                return "Edge(" + convertToString(edge.id()) + "," +
-                        convertToString(edge.outVertex()) + "," +
-                        convertToString(edge.label()) + "," +
-                        convertToString(edge.inVertex()) + ")";
-            } else {
-                final VertexProperty vertexProperty = (VertexProperty) object;
-                return "VertexProperty(" + convertToString(vertexProperty.id()) + "," +
-                        convertToString(vertexProperty.label()) + "," +
-                        convertToString(vertexProperty.value()) + ")";
-            }
-        } else if (object instanceof Lambda)
-            return convertLambdaToString((Lambda) object);
-        else
-            return null == object ? "None" : object.toString();
-    }
-
-    private String convertStatic(final String name) {
-        return this.importStatics ? "" : name;
-    }
-
-    private StringBuilder convertPToString(final P p, final StringBuilder current) {
-        if (p instanceof TextP) return convertTextPToString((TextP) p, current);
-        if (p instanceof ConnectiveP) {
-            final List<P<?>> list = ((ConnectiveP) p).getPredicates();
-            for (int i = 0; i < list.size(); i++) {
-                convertPToString(list.get(i), current);
-                if (i < list.size() - 1)
-                    current.append(p instanceof OrP ? ".or_(" : ".and_(");
-            }
-            current.append(")");
-        } else
-            current.append(convertStatic("P.")).append(p.getBiPredicate().toString()).append("(").append(convertToString(p.getValue())).append(")");
-        return current;
-    }
-
-    private StringBuilder convertTextPToString(final TextP p, final StringBuilder current) {
-        current.append(convertStatic("TextP.")).append(p.getBiPredicate().toString()).append("(").append(convertToString(p.getValue())).append(")");
-        return current;
-    }
-
-    protected String convertLambdaToString(final Lambda lambda) {
-        final String lambdaString = lambda.getLambdaScript().trim();
-        return lambdaString.startsWith("lambda") ? lambdaString : "lambda " + lambdaString;
-    }
-
-    protected String resolveSymbol(final String methodName) {
-        return SymbolHelper.toPython(methodName);
-    }
-
-    protected String resolveTraversalStrategyProxy(final TraversalStrategyProxy proxy) {
-        if (proxy.getConfiguration().isEmpty())
-            return "TraversalStrategy(\"" + proxy.getStrategyClass().getSimpleName() + "\")";
-        else
-            return "TraversalStrategy(\"" + proxy.getStrategyClass().getSimpleName() + "\"," + convertToString(ConfigurationConverter.getMap(proxy.getConfiguration())) + ")";
-    }
-}
diff --git a/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/SymbolHelper.java b/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/SymbolHelper.java
deleted file mode 100644
index 54cd5b3..0000000
--- a/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/SymbolHelper.java
+++ /dev/null
@@ -1,65 +0,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.
- */
-
-package org.apache.tinkerpop.gremlin.python.jsr223;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * @deprecated As of release 3.3.10, not replaced - see TINKERPOP-2317
- *
- * @author Marko A. Rodriguez (http://markorodriguez.com)
- */
-@Deprecated
-public final class SymbolHelper {
-
-    private final static Map<String, String> TO_PYTHON_MAP = new HashMap<>();
-    private final static Map<String, String> FROM_PYTHON_MAP = new HashMap<>();
-
-    static {
-        TO_PYTHON_MAP.put("global", "global_");
-        TO_PYTHON_MAP.put("as", "as_");
-        TO_PYTHON_MAP.put("in", "in_");
-        TO_PYTHON_MAP.put("and", "and_");
-        TO_PYTHON_MAP.put("or", "or_");
-        TO_PYTHON_MAP.put("is", "is_");
-        TO_PYTHON_MAP.put("not", "not_");
-        TO_PYTHON_MAP.put("from", "from_");
-        TO_PYTHON_MAP.put("list", "list_");
-        TO_PYTHON_MAP.put("set", "set_");
-        TO_PYTHON_MAP.put("all", "all_");
-        TO_PYTHON_MAP.put("with", "with_");
-        //
-        TO_PYTHON_MAP.forEach((k, v) -> FROM_PYTHON_MAP.put(v, k));
-    }
-
-    private SymbolHelper() {
-        // static methods only, do not instantiate
-    }
-
-    public static String toPython(final String symbol) {
-        return TO_PYTHON_MAP.getOrDefault(symbol, symbol);
-    }
-
-    public static String toJava(final String symbol) {
-        return FROM_PYTHON_MAP.getOrDefault(symbol, symbol);
-    }
-
-}
diff --git a/gremlin-python/src/main/jython/gremlin_python/driver/client.py b/gremlin-python/src/main/jython/gremlin_python/driver/client.py
deleted file mode 100644
index f1cb451..0000000
--- a/gremlin-python/src/main/jython/gremlin_python/driver/client.py
+++ /dev/null
@@ -1,151 +0,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.
-#
-from concurrent.futures import ThreadPoolExecutor
-
-from six.moves import queue
-
-from gremlin_python.driver import connection, protocol, request, serializer
-from gremlin_python.process import traversal
-
-# This is until concurrent.futures backport 3.1.0 release
-try:
-    from multiprocessing import cpu_count
-except ImportError:
-    # some platforms don't have multiprocessing
-    def cpu_count():
-        return None
-
-__author__ = 'David M. Brown (davebshow@gmail.com)'
-
-
-class Client:
-
-    def __init__(self, url, traversal_source, protocol_factory=None,
-                 transport_factory=None, pool_size=None, max_workers=None,
-                 message_serializer=None, username="", password="",
-                 headers=None, session="", max_content_length=None):
-        self._url = url
-        self._headers = headers
-        self._traversal_source = traversal_source
-        if max_content_length is None:
-            max_content_length = 10 * 1024 * 1024
-        if message_serializer is None:
-            message_serializer = serializer.GraphSONSerializersV3d0()
-        self._message_serializer = message_serializer
-        self._username = username
-        self._password = password
-        self._session = session
-        self._sessionEnabled = (session != "")
-        if transport_factory is None:
-            try:
-                from gremlin_python.driver.tornado.transport import (
-                    TornadoTransport)
-            except ImportError:
-                raise Exception("Please install Tornado or pass"
-                                "custom transport factory")
-            else:
-                transport_factory = lambda: TornadoTransport(
-                    max_content_length=max_content_length)
-        self._transport_factory = transport_factory
-        if protocol_factory is None:
-            protocol_factory = lambda: protocol.GremlinServerWSProtocol(
-                self._message_serializer,
-                username=self._username,
-                password=self._password)
-        self._protocol_factory = protocol_factory
-        if self._sessionEnabled:
-            if pool_size is None:
-                pool_size = 1
-            elif pool_size != 1:
-                raise Exception("PoolSize must be 1 on session mode!")
-        if pool_size is None:
-            pool_size = 4
-        self._pool_size = pool_size
-        # This is until concurrent.futures backport 3.1.0 release
-        if max_workers is None:
-            # If your application is overlapping Gremlin I/O on multiple threads
-            # consider passing kwarg max_workers = (cpu_count() or 1) * 5
-            max_workers = pool_size
-        self._executor = ThreadPoolExecutor(max_workers=max_workers)
-        # Threadsafe queue
-        self._pool = queue.Queue()
-        self._fill_pool()
-
-    @property
-    def available_pool_size(self):
-        return self._pool.qsize()
-
-    @property
-    def executor(self):
-        return self._executor
-
-    @property
-    def traversal_source(self):
-        return self._traversal_source
-
-    def _fill_pool(self):
-        for i in range(self._pool_size):
-            conn = self._get_connection()
-            self._pool.put_nowait(conn)
-
-    def close(self):
-        if self._sessionEnabled:
-            self._close_session()
-        while not self._pool.empty():
-            conn = self._pool.get(True)
-            conn.close()
-        self._executor.shutdown()
-
-    def _close_session(self):
-        message = request.RequestMessage(
-            processor='session', op='close',
-            args={'session': self._session})
-        conn = self._pool.get(True)
-        return conn.write(message).result()
-
-    def _get_connection(self):
-        protocol = self._protocol_factory()
-        return connection.Connection(
-            self._url, self._traversal_source, protocol,
-            self._transport_factory, self._executor, self._pool,
-            headers=self._headers)
-
-    def submit(self, message, bindings=None, request_options=None):
-        return self.submitAsync(message, bindings=bindings, request_options=request_options).result()
-
-    def submitAsync(self, message, bindings=None, request_options=None):
-        if isinstance(message, traversal.Bytecode):
-            message = request.RequestMessage(
-                processor='traversal', op='bytecode',
-                args={'gremlin': message,
-                      'aliases': {'g': self._traversal_source}})
-        elif isinstance(message, str):
-            message = request.RequestMessage(
-                processor='', op='eval',
-                args={'gremlin': message,
-                      'aliases': {'g': self._traversal_source}})
-            if bindings:
-                message.args.update({'bindings': bindings})
-            if self._sessionEnabled:
-                message = message._replace(processor='session')
-                message.args.update({'session': self._session})
-        conn = self._pool.get(True)
-        if request_options:
-            message.args.update(request_options)
-        return conn.write(message)
diff --git a/gremlin-python/src/main/jython/gremlin_python/driver/driver_remote_connection.py b/gremlin-python/src/main/jython/gremlin_python/driver/driver_remote_connection.py
deleted file mode 100644
index bc7b57b..0000000
--- a/gremlin-python/src/main/jython/gremlin_python/driver/driver_remote_connection.py
+++ /dev/null
@@ -1,89 +0,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.
-#
-from concurrent.futures import Future
-
-from gremlin_python.driver import client, serializer
-from gremlin_python.driver.remote_connection import (
-    RemoteConnection, RemoteTraversal, RemoteTraversalSideEffects)
-from gremlin_python.process.strategies import OptionsStrategy
-
-__author__ = 'David M. Brown (davebshow@gmail.com)'
-
-
-class DriverRemoteConnection(RemoteConnection):
-
-    def __init__(self, url, traversal_source, protocol_factory=None,
-                 transport_factory=None, pool_size=None, max_workers=None,
-                 username="", password="", message_serializer=None,
-                 graphson_reader=None, graphson_writer=None,
-                 headers=None, max_content_length=None):
-        if message_serializer is None:
-            message_serializer = serializer.GraphSONMessageSerializer(
-                reader=graphson_reader,
-                writer=graphson_writer)
-        self._client = client.Client(url, traversal_source,
-                                     protocol_factory=protocol_factory,
-                                     transport_factory=transport_factory,
-                                     pool_size=pool_size,
-                                     max_workers=max_workers,
-                                     message_serializer=message_serializer,
-                                     username=username,
-                                     password=password,
-                                     headers=headers,
-                                     max_content_length=max_content_length)
-        self._url = self._client._url
-        self._traversal_source = self._client._traversal_source
-
-    def close(self):
-        self._client.close()
-
-    def submit(self, bytecode):
-        result_set = self._client.submit(bytecode, request_options=self._extract_request_options(bytecode))
-        results = result_set.all().result()
-        side_effects = RemoteTraversalSideEffects(result_set.request_id, self._client,
-                                                  result_set.status_attributes)
-        return RemoteTraversal(iter(results), side_effects)
-
-    def submitAsync(self, bytecode):
-        future = Future()
-        future_result_set = self._client.submitAsync(bytecode, request_options=self._extract_request_options(bytecode))
-
-        def cb(f):
-            try:
-                result_set = f.result()
-                results = result_set.all().result()
-                side_effects = RemoteTraversalSideEffects(result_set.request_id, self._client,
-                                                          result_set.status_attributes)
-                future.set_result(RemoteTraversal(iter(results), side_effects))
-            except Exception as e:
-                future.set_exception(e)
-
-        future_result_set.add_done_callback(cb)
-        return future
-
-    @staticmethod
-    def _extract_request_options(bytecode):
-        options_strategy = next((x for x in bytecode.source_instructions
-                                 if x[0] == "withStrategies" and type(x[1]) is OptionsStrategy), None)
-        request_options = None
-        if options_strategy:
-            allowed_keys = ['evaluationTimeout', 'scriptEvaluationTimeout', 'batchSize', 'requestId', 'userAgent']
-            request_options = {allowed: options_strategy[1].configuration[allowed] for allowed in allowed_keys
-                               if allowed in options_strategy[1].configuration}
-        return request_options
diff --git a/gremlin-python/src/main/jython/gremlin_python/driver/protocol.py b/gremlin-python/src/main/jython/gremlin_python/driver/protocol.py
deleted file mode 100644
index ad0d467..0000000
--- a/gremlin-python/src/main/jython/gremlin_python/driver/protocol.py
+++ /dev/null
@@ -1,112 +0,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.
-#
-import abc
-import base64
-
-import six
-
-try:
-    import ujson as json
-except ImportError:
-    import json
-
-from gremlin_python.driver import serializer, request
-from gremlin_python.driver.resultset import ResultSet
-
-__author__ = 'David M. Brown (davebshow@gmail.com)'
-
-
-class GremlinServerError(Exception):
-    def __init__(self, status):
-        super(GremlinServerError, self).__init__("{0}: {1}".format(status["code"], status["message"]))
-        self._status_attributes = status["attributes"]
-        self.status_code = status["code"]
-
-    @property
-    def status_attributes(self):
-        return self._status_attributes
-
-
-@six.add_metaclass(abc.ABCMeta)
-class AbstractBaseProtocol:
-
-    @abc.abstractmethod
-    def connection_made(self, transport):
-        self._transport = transport
-
-    @abc.abstractmethod
-    def data_received(self, message):
-        pass
-
-    @abc.abstractmethod
-    def write(self, request_id, request_message):
-        pass
-
-
-class GremlinServerWSProtocol(AbstractBaseProtocol):
-
-    def __init__(self, message_serializer, username='', password=''):
-        self._message_serializer = message_serializer
-        self._username = username
-        self._password = password
-
-    def connection_made(self, transport):
-        super(GremlinServerWSProtocol, self).connection_made(transport)
-
-    def write(self, request_id, request_message):
-        message = self._message_serializer.serialize_message(
-            request_id, request_message)
-        self._transport.write(message)
-
-    def data_received(self, message, results_dict):
-        # if Gremlin Server cuts off then we get a None for the message
-        if message is None:
-            raise GremlinServerError({'code': 500, 
-                                      'message': 'Server disconnected - please try to reconnect', 'attributes': {}})
-
-        message = self._message_serializer.deserialize_message(message)
-        request_id = message['requestId']
-        result_set = results_dict[request_id] if request_id in results_dict else ResultSet(None, None)
-        status_code = message['status']['code']
-        aggregate_to = message['result']['meta'].get('aggregateTo', 'list')
-        data = message['result']['data']
-        result_set.aggregate_to = aggregate_to
-        if status_code == 407:
-            auth = b''.join([b'\x00', self._username.encode('utf-8'),
-                             b'\x00', self._password.encode('utf-8')])
-            request_message = request.RequestMessage(
-                'traversal', 'authentication',
-                {'sasl': base64.b64encode(auth).decode()})
-            self.write(request_id, request_message)
-            data = self._transport.read()
-            # Allow recursive call for auth
-            return self.data_received(data, results_dict)
-        elif status_code == 204:
-            result_set.stream.put_nowait([])
-            del results_dict[request_id]
-            return status_code
-        elif status_code in [200, 206]:
-            result_set.stream.put_nowait(data)
-            if status_code == 200:
-                result_set.status_attributes = message['status']['attributes']
-                del results_dict[request_id]
-            return status_code
-        else:
-            del results_dict[request_id]
-            raise GremlinServerError(message["status"])
diff --git a/gremlin-python/src/main/jython/gremlin_python/driver/remote_connection.py b/gremlin-python/src/main/jython/gremlin_python/driver/remote_connection.py
deleted file mode 100644
index 6b6de14..0000000
--- a/gremlin-python/src/main/jython/gremlin_python/driver/remote_connection.py
+++ /dev/null
@@ -1,157 +0,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.
-#
-import abc
-import six
-
-from gremlin_python.driver import request
-from gremlin_python.process import traversal
-
-__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
-
-
-@six.add_metaclass(abc.ABCMeta)
-class RemoteConnection(object):
-    def __init__(self, url, traversal_source):
-        self._url = url
-        self._traversal_source = traversal_source
-
-    @property
-    def url(self):
-        return self._url
-
-    @property
-    def traversal_source(self):
-        return self._traversal_source
-
-    @abc.abstractmethod
-    def submit(self, bytecode):
-        pass
-
-    def __repr__(self):
-        return "remoteconnection[" + self._url + "," + self._traversal_source + "]"
-
-
-class RemoteTraversal(traversal.Traversal):
-    def __init__(self, traversers, side_effects):
-        super(RemoteTraversal, self).__init__(None, None, None)
-        self.traversers = traversers
-        self._side_effects = side_effects
-
-    @property
-    def side_effects(self):
-        return self._side_effects
-
-    @side_effects.setter
-    def side_effects(self, val):
-        self._side_effects = val
-
-
-class RemoteTraversalSideEffects(traversal.TraversalSideEffects):
-    def __init__(self, side_effect, client, status_attributes):
-        self._side_effect = side_effect
-        self._client = client
-        self._keys = set()
-        self._side_effects = {}
-        self._closed = False
-        self._status_attributes = status_attributes
-
-    @property
-    def status_attributes(self):
-        return self._status_attributes
-
-    def keys(self):
-        if not self._closed:
-            message = request.RequestMessage(
-                'traversal', 'keys',
-                {'sideEffect': self._side_effect,
-                'aliases': {'g': self._client.traversal_source}})
-            self._keys = set(self._client.submit(message).all().result())
-        return self._keys
-
-    def get(self, key):
-
-        if not self._side_effects.get(key):
-            if not self._closed:
-                message = request.RequestMessage(
-                    'traversal', 'gather',
-                    {'sideEffect': self._side_effect, 'sideEffectKey': key,
-                     'aliases': {'g': self._client.traversal_source}})
-                results = self._aggregate_results(self._client.submit(message))
-                self._side_effects[key] = results
-                self._keys.add(key)
-            else:
-                return None
-        return self._side_effects[key]
-
-    def close(self):
-        if not self._closed:
-            message = request.RequestMessage(
-                'traversal', 'close',
-                {'sideEffect': self._side_effect,
-                 'aliases': {'g': self._client._traversal_source}})
-            results = self._client.submit(message).all().result()
-        self._closed = True
-        return results
-
-    def _aggregate_results(self, result_set):
-        aggregates = {'list': [], 'set': set(), 'map': {}, 'bulkset': {},
-                      'none': None}
-        results = None
-        for msg in result_set:
-            if results is None:
-                aggregate_to = result_set.aggregate_to
-                results = aggregates.get(aggregate_to, [])
-            # on first message, get the right result data structure
-            # if there is no update to a structure, then the item is the result
-            if results is None:
-                results = msg[0]
-            # updating a map is different than a list or a set
-            elif isinstance(results, dict):
-                if aggregate_to == "map":
-                    for item in msg:
-                        results.update(item)
-                else:
-                    for item in msg:
-                        results[item.object] = item.bulk
-            elif isinstance(results, set):
-                results.update(msg)
-            # flat add list to result list
-            else:
-                results += msg
-        if results is None:
-            results = []
-        return results
-
-
-class RemoteStrategy(traversal.TraversalStrategy):
-    def __init__(self, remote_connection):
-        traversal.TraversalStrategy.__init__(self)
-        self.remote_connection = remote_connection
-
-    def apply(self, traversal):
-        if traversal.traversers is None:
-            remote_traversal = self.remote_connection.submit(traversal.bytecode)
-            traversal.remote_results = remote_traversal
-            traversal.side_effects = remote_traversal.side_effects
-            traversal.traversers = remote_traversal.traversers
-
-    def apply_async(self, traversal):
-        if traversal.traversers is None:
-            traversal.remote_results = self.remote_connection.submitAsync(
-                traversal.bytecode)
diff --git a/gremlin-python/src/main/jython/gremlin_python/driver/serializer.py b/gremlin-python/src/main/jython/gremlin_python/driver/serializer.py
deleted file mode 100644
index c7b6b4d..0000000
--- a/gremlin-python/src/main/jython/gremlin_python/driver/serializer.py
+++ /dev/null
@@ -1,293 +0,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.
-#
-try:
-    import ujson as json
-except ImportError:
-    import json
-import struct
-import uuid
-import io
-
-from gremlin_python.structure.io import graphbinaryV1
-from gremlin_python.structure.io import graphsonV2d0
-from gremlin_python.structure.io import graphsonV3d0
-
-__author__ = 'David M. Brown (davebshow@gmail.com)'
-
-
-class Processor:
-    """Base class for OpProcessor serialization system."""
-
-    def __init__(self, writer):
-        self._writer = writer
-
-    def get_op_args(self, op, args):
-        op_method = getattr(self, op, None)
-        if not op_method:
-            raise Exception("Processor does not support op: {}".format(op))
-        return op_method(args)
-
-
-class Standard(Processor):
-
-    def authentication(self, args):
-        return args
-
-    def eval(self, args):
-        return args
-
-
-class Session(Processor):
-
-    def authentication(self, args):
-        return args
-
-    def eval(self, args):
-        return args
-
-    def close(self, args):
-        return args
-
-class Traversal(Processor):
-
-    def authentication(self, args):
-        return args
-
-    def bytecode(self, args):
-        gremlin = args['gremlin']
-        args['gremlin'] = self._writer.toDict(gremlin)
-        aliases = args.get('aliases', '')
-        if not aliases:
-            aliases = {'g': 'g'}
-        args['aliases'] = aliases
-        return args
-
-    def close(self, args):
-        return self.keys(args)
-
-    def gather(self, args):
-        side_effect = uuid.UUID(args['sideEffect'])
-        args['sideEffect'] = self._writer.toDict(side_effect)
-        aliases = args.get('aliases', '')
-        if not aliases:
-            aliases = {'g': 'g'}
-        args['aliases'] = aliases
-        return args
-
-    def keys(self, args):
-        side_effect = uuid.UUID(args['sideEffect'])
-        args['sideEffect'] = self._writer.toDict(side_effect)
-        return args
-
-
-class GraphSONMessageSerializer(object):
-    """
-    Message serializer for GraphSON. Allow users to pass custom reader,
-    writer, and version kwargs for custom serialization. Otherwise,
-    use current GraphSON version as default.
-    """
-
-    # KEEP TRACK OF CURRENT DEFAULTS
-    DEFAULT_READER_CLASS = graphsonV3d0.GraphSONReader
-    DEFAULT_WRITER_CLASS = graphsonV3d0.GraphSONWriter
-    DEFAULT_VERSION = b"application/vnd.gremlin-v3.0+json"
-
-    def __init__(self, reader=None, writer=None, version=None):
-        if not version:
-            version = self.DEFAULT_VERSION
-        self._version = version
-        if not reader:
-            reader = self.DEFAULT_READER_CLASS()
-        self._graphson_reader = reader
-        if not writer:
-            writer = self.DEFAULT_WRITER_CLASS()
-        self.standard = Standard(writer)
-        self.traversal = Traversal(writer)
-        self.session = Session(writer)
-
-    @property
-    def version(self):
-        """Read only property"""
-        return self._version
-
-    def get_processor(self, processor):
-        processor = getattr(self, processor, None)
-        if not processor:
-            raise Exception("Unknown processor")
-        return processor
-
-    def serialize_message(self, request_id, request_message):
-        processor = request_message.processor
-        op = request_message.op
-        args = request_message.args
-        if not processor:
-            processor_obj = self.get_processor('standard')
-        else:
-            processor_obj = self.get_processor(processor)
-        args = processor_obj.get_op_args(op, args)
-        message = self.build_message(request_id, processor, op, args)
-        return message
-
-    def build_message(self, request_id, processor, op, args):
-        message = {
-            'requestId': {'@type': 'g:UUID', '@value': request_id},
-            'processor': processor,
-            'op': op,
-            'args': args
-        }
-        return self.finalize_message(message, b"\x21", self.version)
-
-    def finalize_message(self, message, mime_len, mime_type):
-        message = json.dumps(message)
-        message = b''.join([mime_len, mime_type, message.encode('utf-8')])
-        return message
-
-    def deserialize_message(self, message):
-        msg = json.loads(message.decode('utf-8'))
-        return self._graphson_reader.toObject(msg)
-
-
-class GraphSONSerializersV2d0(GraphSONMessageSerializer):
-    """Message serializer for GraphSON 2.0"""
-    def __init__(self):
-        reader = graphsonV2d0.GraphSONReader()
-        writer = graphsonV2d0.GraphSONWriter()
-        version = b"application/vnd.gremlin-v2.0+json"
-        super(GraphSONSerializersV2d0, self).__init__(reader, writer, version)
-
-
-class GraphSONSerializersV3d0(GraphSONMessageSerializer):
-    """Message serializer for GraphSON 3.0"""
-    def __init__(self):
-        reader = graphsonV3d0.GraphSONReader()
-        writer = graphsonV3d0.GraphSONWriter()
-        version = b"application/vnd.gremlin-v3.0+json"
-        super(GraphSONSerializersV3d0, self).__init__(reader, writer, version)
-
-
-class GraphBinarySerializersV1(object):
-    DEFAULT_READER_CLASS = graphbinaryV1.GraphBinaryReader
-    DEFAULT_WRITER_CLASS = graphbinaryV1.GraphBinaryWriter
-    DEFAULT_VERSION = b"application/vnd.graphbinary-v1.0"
-
-    max_int64 = 0xFFFFFFFFFFFFFFFF
-    header_struct = struct.Struct('>b32sBQQ')
-    header_pack = header_struct.pack
-    int_pack = graphbinaryV1.int32_pack
-    int32_unpack = struct.Struct(">i").unpack
-
-    def __init__(self, reader=None, writer=None, version=None):
-        if not version:
-            version = self.DEFAULT_VERSION
-        self._version = version
-        if not reader:
-            reader = self.DEFAULT_READER_CLASS()
-        self._graphbinary_reader = reader
-        if not writer:
-            writer = self.DEFAULT_WRITER_CLASS()
-        self._graphbinary_writer = writer
-        self.standard = Standard(writer)
-        self.traversal = Traversal(writer)
-
-    @property
-    def version(self):
-        """Read only property"""
-        return self._version
-
-    def get_processor(self, processor):
-        processor = getattr(self, processor, None)
-        if not processor:
-            raise Exception("Unknown processor")
-        return processor
-
-    def serialize_message(self, request_id, request_message):
-        processor = request_message.processor
-        op = request_message.op
-        args = request_message.args
-        if not processor:
-            processor_obj = self.get_processor('standard')
-        else:
-            processor_obj = self.get_processor(processor)
-        args = processor_obj.get_op_args(op, args)
-        message = self.build_message(request_id, processor, op, args)
-        return message
-
-    def build_message(self, request_id, processor, op, args):
-        message = {
-            'requestId': request_id,
-            'processor': processor,
-            'op': op,
-            'args': args
-        }
-        return self.finalize_message(message, 0x20, self.version)
-
-    def finalize_message(self, message, mime_len, mime_type):
-        ba = bytearray()
-
-        request_id = uuid.UUID(message['requestId'])
-        ba.extend(self.header_pack(mime_len, mime_type, 0x81,
-                                   (request_id.int >> 64) & self.max_int64, request_id.int & self.max_int64))
-
-        op_bytes = message['op'].encode("utf-8")
-        ba.extend(self.int_pack(len(op_bytes)))
-        ba.extend(op_bytes)
-
-        processor_bytes = message['processor'].encode("utf-8")
-        ba.extend(self.int_pack(len(processor_bytes)))
-        ba.extend(processor_bytes)
-
-        args = message["args"]
-        ba.extend(self.int_pack(len(args)))
-        for k, v in args.items():
-            self._graphbinary_writer.toDict(k, ba)
-
-            # processor_obj.get_op_args in serialize_message() seems to already handle bytecode. in python 3
-            # because bytearray isn't bound to a type in graphbinary it falls through the writeObject() and
-            # just works but python 2 bytearray is bound to ByteBufferType so it writes DataType.bytebuffer
-            # rather than DataType.bytecode and the server gets confused. special casing this for now until
-            # it can be refactored
-            if k == "gremlin" or k == "sideEffect":
-                ba.extend(v)
-            else:
-                self._graphbinary_writer.toDict(v, ba)
-
-        return bytes(ba)
-
-    def deserialize_message(self, message):
-        b = io.BytesIO(message)
-
-        b.read(1)  # version
-
-        request_id = str(self._graphbinary_reader.toObject(b, graphbinaryV1.DataType.uuid))
-        status_code = self.int32_unpack(b.read(4))[0]
-        status_msg = self._graphbinary_reader.toObject(b, graphbinaryV1.DataType.string)
-        status_attrs = self._graphbinary_reader.toObject(b, graphbinaryV1.DataType.map, nullable=False)
-        meta_attrs = self._graphbinary_reader.toObject(b, graphbinaryV1.DataType.map, nullable=False)
-        result = self._graphbinary_reader.toObject(b)
-
-        b.close()
-
-        msg = {'requestId': request_id,
-               'status': {'code': status_code,
-                          'message': status_msg,
-                          'attributes': status_attrs},
-               'result': {'meta': meta_attrs,
-                          'data': result}}
-
-        return msg
diff --git a/gremlin-python/src/main/jython/gremlin_python/driver/tornado/__init__.py b/gremlin-python/src/main/jython/gremlin_python/driver/tornado/__init__.py
deleted file mode 100644
index 44d3f2d..0000000
--- a/gremlin-python/src/main/jython/gremlin_python/driver/tornado/__init__.py
+++ /dev/null
@@ -1,18 +0,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.
-#
diff --git a/gremlin-python/src/main/jython/gremlin_python/driver/tornado/transport.py b/gremlin-python/src/main/jython/gremlin_python/driver/tornado/transport.py
deleted file mode 100644
index cd0b4bf..0000000
--- a/gremlin-python/src/main/jython/gremlin_python/driver/tornado/transport.py
+++ /dev/null
@@ -1,61 +0,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.
-#
-from tornado import ioloop, websocket
-from tornado import httpclient
-
-from gremlin_python.driver.transport import AbstractBaseTransport
-
-__author__ = 'David M. Brown (davebshow@gmail.com)'
-
-
-class TornadoTransport(AbstractBaseTransport):
-
-    _default_max_content_length = 10 * 1024 * 1024
-
-    def __init__(self, read_timeout=None, write_timeout=None,
-                 compression_options={'compression_level': 5, 'mem_level': 5},
-                 ssl_options=None, max_content_length=_default_max_content_length):
-        self._loop = ioloop.IOLoop(make_current=False)
-        self._ws = None
-        self._read_timeout = read_timeout
-        self._write_timeout = write_timeout
-        self._compression_options = compression_options
-        self._ssl_options = ssl_options
-        self._max_content_length = max_content_length
-
-    def connect(self, url, headers=None):
-        if headers or self._ssl_options:
-            url = httpclient.HTTPRequest(url, headers=headers, ssl_options=self._ssl_options)
-        self._ws = self._loop.run_sync(
-            lambda: websocket.websocket_connect(url, compression_options=self._compression_options,
-                                                max_message_size=self._max_content_length))
-
-    def write(self, message):
-        self._loop.run_sync(
-            lambda: self._ws.write_message(message, binary=True), timeout=self._write_timeout)
-
-    def read(self):
-        return self._loop.run_sync(lambda: self._ws.read_message(), timeout=self._read_timeout)
-
-    def close(self):
-        self._ws.close()
-        self._loop.close()
-
-    def closed(self):
-        return not self._ws.protocol
diff --git a/gremlin-python/src/main/jython/gremlin_python/driver/transport.py b/gremlin-python/src/main/jython/gremlin_python/driver/transport.py
deleted file mode 100644
index ebdc325..0000000
--- a/gremlin-python/src/main/jython/gremlin_python/driver/transport.py
+++ /dev/null
@@ -1,46 +0,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.
-#
-import abc
-import six
-
-__author__ = 'David M. Brown (davebshow@gmail.com)'
-
-
-@six.add_metaclass(abc.ABCMeta)
-class AbstractBaseTransport:
-
-    @abc.abstractmethod
-    def connect(self, url, headers=None):
-        pass
-
-    @abc.abstractmethod
-    def write(self, message):
-        pass
-
-    @abc.abstractmethod
-    def read(self):
-        pass
-
-    @abc.abstractmethod
-    def close(self):
-        pass
-
-    @abc.abstractproperty
-    def closed(self):
-        pass
diff --git a/gremlin-python/src/main/jython/gremlin_python/process/graph_traversal.py b/gremlin-python/src/main/jython/gremlin_python/process/graph_traversal.py
deleted file mode 100644
index edf4ddf..0000000
--- a/gremlin-python/src/main/jython/gremlin_python/process/graph_traversal.py
+++ /dev/null
@@ -1,1579 +0,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.
-#
-
-import sys
-import copy
-from .traversal import Traversal
-from .traversal import TraversalStrategies
-from .strategies import VertexProgramStrategy, OptionsStrategy
-from .traversal import Bytecode
-from ..driver.remote_connection import RemoteStrategy
-from .. import statics
-from ..statics import long
-
-
-class GraphTraversalSource(object):
-    def __init__(self, graph, traversal_strategies, bytecode=None):
-        self.graph = graph
-        self.traversal_strategies = traversal_strategies
-        if bytecode is None:
-          bytecode = Bytecode()
-        self.bytecode = bytecode
-        self.graph_traversal = GraphTraversal
-
-    def __repr__(self):
-        return "graphtraversalsource[" + str(self.graph) + "]"
-
-    def get_graph_traversal_source(self):
-        return self.__class__(self.graph, TraversalStrategies(self.traversal_strategies), Bytecode(self.bytecode))
-
-    def get_graph_traversal(self):
-        return self.graph_traversal(self.graph, self.traversal_strategies, Bytecode(self.bytecode))
-
-    def withBulk(self, *args):
-        source = self.get_graph_traversal_source()
-        source.bytecode.add_source("withBulk", *args)
-        return source
-
-    def withPath(self, *args):
-        source = self.get_graph_traversal_source()
-        source.bytecode.add_source("withPath", *args)
-        return source
-
-    def withSack(self, *args):
-        source = self.get_graph_traversal_source()
-        source.bytecode.add_source("withSack", *args)
-        return source
-
-    def withSideEffect(self, *args):
-        source = self.get_graph_traversal_source()
-        source.bytecode.add_source("withSideEffect", *args)
-        return source
-
-    def withStrategies(self, *args):
-        source = self.get_graph_traversal_source()
-        source.bytecode.add_source("withStrategies", *args)
-        return source
-
-    def withoutStrategies(self, *args):
-        source = self.get_graph_traversal_source()
-        source.bytecode.add_source("withoutStrategies", *args)
-        return source
-
-    def with_(self, k, v=None):
-        source = self.get_graph_traversal_source()
-        options_strategy = next((x for x in source.bytecode.source_instructions
-                                if x[0] == "withStrategies" and type(x[1]) is OptionsStrategy), None)
-
-        val = True if v is None else v
-        if options_strategy is None:
-            options_strategy = OptionsStrategy({k: val})
-            source = self.withStrategies(options_strategy)
-        else:
-            options_strategy[1].configuration[k] = val
-
-        return source
-
-    def withRemote(self, remote_connection):
-        source = self.get_graph_traversal_source()
-        source.traversal_strategies.add_strategies([RemoteStrategy(remote_connection)])
-        return source
-
-    def withComputer(self, graph_computer=None, workers=None, result=None, persist=None, vertices=None,
-                     edges=None, configuration=None):
-        return self.withStrategies(VertexProgramStrategy(graph_computer, workers, result, persist, vertices,
-                                   edges, configuration))
-
-    def E(self, *args):
-        traversal = self.get_graph_traversal()
-        traversal.bytecode.add_step("E", *args)
-        return traversal
-
-    def V(self, *args):
-        traversal = self.get_graph_traversal()
-        traversal.bytecode.add_step("V", *args)
-        return traversal
-
-    def addE(self, *args):
-        traversal = self.get_graph_traversal()
-        traversal.bytecode.add_step("addE", *args)
-        return traversal
-
-    def addV(self, *args):
-        traversal = self.get_graph_traversal()
-        traversal.bytecode.add_step("addV", *args)
-        return traversal
-
-    def inject(self, *args):
-        traversal = self.get_graph_traversal()
-        traversal.bytecode.add_step("inject", *args)
-        return traversal
-
-    def io(self, *args):
-        traversal = self.get_graph_traversal()
-        traversal.bytecode.add_step("io", *args)
-        return traversal
-
-
-class GraphTraversal(Traversal):
-    def __init__(self, graph, traversal_strategies, bytecode):
-        super(GraphTraversal, self).__init__(graph, traversal_strategies, bytecode)
-
-    def __getitem__(self, index):
-        if isinstance(index, int):
-            return self.range(long(index), long(index + 1))
-        elif isinstance(index, slice):
-            low = long(0) if index.start is None else long(index.start)
-            high = long(sys.maxsize) if index.stop is None else long(index.stop)
-            if low == long(0):
-                return self.limit(high)
-            else:
-                return self.range(low,high)
-        else:
-            raise TypeError("Index must be int or slice")
-
-    def __getattr__(self, key):
-        if key.startswith('__'):
-            raise AttributeError(
-                'Python magic methods or keys starting with double underscore cannot be used for Gremlin sugar - prefer values(' + key + ')')
-        return self.values(key)
-
-    def clone(self):
-        return GraphTraversal(self.graph, self.traversal_strategies, copy.deepcopy(self.bytecode))
-
-    def V(self, *args):
-        self.bytecode.add_step("V", *args)
-        return self
-
-    def addE(self, *args):
-        self.bytecode.add_step("addE", *args)
-        return self
-
-    def addV(self, *args):
-        self.bytecode.add_step("addV", *args)
-        return self
-
-    def aggregate(self, *args):
-        self.bytecode.add_step("aggregate", *args)
-        return self
-
-    def and_(self, *args):
-        self.bytecode.add_step("and", *args)
-        return self
-
-    def as_(self, *args):
-        self.bytecode.add_step("as", *args)
-        return self
-
-    def barrier(self, *args):
-        self.bytecode.add_step("barrier", *args)
-        return self
-
-    def both(self, *args):
-        self.bytecode.add_step("both", *args)
-        return self
-
-    def bothE(self, *args):
-        self.bytecode.add_step("bothE", *args)
-        return self
-
-    def bothV(self, *args):
-        self.bytecode.add_step("bothV", *args)
-        return self
-
-    def branch(self, *args):
-        self.bytecode.add_step("branch", *args)
-        return self
-
-    def by(self, *args):
-        self.bytecode.add_step("by", *args)
-        return self
-
-    def cap(self, *args):
-        self.bytecode.add_step("cap", *args)
-        return self
-
-    def choose(self, *args):
-        self.bytecode.add_step("choose", *args)
-        return self
-
-    def coalesce(self, *args):
-        self.bytecode.add_step("coalesce", *args)
-        return self
-
-    def coin(self, *args):
-        self.bytecode.add_step("coin", *args)
-        return self
-
-    def connectedComponent(self, *args):
-        self.bytecode.add_step("connectedComponent", *args)
-        return self
-
-    def constant(self, *args):
-        self.bytecode.add_step("constant", *args)
-        return self
-
-    def count(self, *args):
-        self.bytecode.add_step("count", *args)
-        return self
-
-    def cyclicPath(self, *args):
-        self.bytecode.add_step("cyclicPath", *args)
-        return self
-
-    def dedup(self, *args):
-        self.bytecode.add_step("dedup", *args)
-        return self
-
-    def drop(self, *args):
-        self.bytecode.add_step("drop", *args)
-        return self
-
-    def elementMap(self, *args):
-        self.bytecode.add_step("elementMap", *args)
-        return self
-
-    def emit(self, *args):
-        self.bytecode.add_step("emit", *args)
-        return self
-
-    def filter_(self, *args):
-        self.bytecode.add_step("filter", *args)
-        return self
-
-    def flatMap(self, *args):
-        self.bytecode.add_step("flatMap", *args)
-        return self
-
-    def fold(self, *args):
-        self.bytecode.add_step("fold", *args)
-        return self
-
-    def from_(self, *args):
-        self.bytecode.add_step("from", *args)
-        return self
-
-    def group(self, *args):
-        self.bytecode.add_step("group", *args)
-        return self
-
-    def groupCount(self, *args):
-        self.bytecode.add_step("groupCount", *args)
-        return self
-
-    def has(self, *args):
-        self.bytecode.add_step("has", *args)
-        return self
-
-    def hasId(self, *args):
-        self.bytecode.add_step("hasId", *args)
-        return self
-
-    def hasKey(self, *args):
-        self.bytecode.add_step("hasKey", *args)
-        return self
-
-    def hasLabel(self, *args):
-        self.bytecode.add_step("hasLabel", *args)
-        return self
-
-    def hasNot(self, *args):
-        self.bytecode.add_step("hasNot", *args)
-        return self
-
-    def hasValue(self, *args):
-        self.bytecode.add_step("hasValue", *args)
-        return self
-
-    def id_(self, *args):
-        self.bytecode.add_step("id", *args)
-        return self
-
-    def identity(self, *args):
-        self.bytecode.add_step("identity", *args)
-        return self
-
-    def inE(self, *args):
-        self.bytecode.add_step("inE", *args)
-        return self
-
-    def inV(self, *args):
-        self.bytecode.add_step("inV", *args)
-        return self
-
-    def in_(self, *args):
-        self.bytecode.add_step("in", *args)
-        return self
-
-    def index(self, *args):
-        self.bytecode.add_step("index", *args)
-        return self
-
-    def inject(self, *args):
-        self.bytecode.add_step("inject", *args)
-        return self
-
-    def is_(self, *args):
-        self.bytecode.add_step("is", *args)
-        return self
-
-    def key(self, *args):
-        self.bytecode.add_step("key", *args)
-        return self
-
-    def label(self, *args):
-        self.bytecode.add_step("label", *args)
-        return self
-
-    def limit(self, *args):
-        self.bytecode.add_step("limit", *args)
-        return self
-
-    def local(self, *args):
-        self.bytecode.add_step("local", *args)
-        return self
-
-    def loops(self, *args):
-        self.bytecode.add_step("loops", *args)
-        return self
-
-    def map(self, *args):
-        self.bytecode.add_step("map", *args)
-        return self
-
-    def match(self, *args):
-        self.bytecode.add_step("match", *args)
-        return self
-
-    def math(self, *args):
-        self.bytecode.add_step("math", *args)
-        return self
-
-    def max_(self, *args):
-        self.bytecode.add_step("max", *args)
-        return self
-
-    def mean(self, *args):
-        self.bytecode.add_step("mean", *args)
-        return self
-
-    def min_(self, *args):
-        self.bytecode.add_step("min", *args)
-        return self
-
-    def none(self, *args):
-        self.bytecode.add_step("none", *args)
-        return self
-
-    def not_(self, *args):
-        self.bytecode.add_step("not", *args)
-        return self
-
-    def option(self, *args):
-        self.bytecode.add_step("option", *args)
-        return self
-
-    def optional(self, *args):
-        self.bytecode.add_step("optional", *args)
-        return self
-
-    def or_(self, *args):
-        self.bytecode.add_step("or", *args)
-        return self
-
-    def order(self, *args):
-        self.bytecode.add_step("order", *args)
-        return self
-
-    def otherV(self, *args):
-        self.bytecode.add_step("otherV", *args)
-        return self
-
-    def out(self, *args):
-        self.bytecode.add_step("out", *args)
-        return self
-
-    def outE(self, *args):
-        self.bytecode.add_step("outE", *args)
-        return self
-
-    def outV(self, *args):
-        self.bytecode.add_step("outV", *args)
-        return self
-
-    def pageRank(self, *args):
-        self.bytecode.add_step("pageRank", *args)
-        return self
-
-    def path(self, *args):
-        self.bytecode.add_step("path", *args)
-        return self
-
-    def peerPressure(self, *args):
-        self.bytecode.add_step("peerPressure", *args)
-        return self
-
-    def profile(self, *args):
-        self.bytecode.add_step("profile", *args)
-        return self
-
-    def program(self, *args):
-        self.bytecode.add_step("program", *args)
-        return self
-
-    def project(self, *args):
-        self.bytecode.add_step("project", *args)
-        return self
-
-    def properties(self, *args):
-        self.bytecode.add_step("properties", *args)
-        return self
-
-    def property(self, *args):
-        self.bytecode.add_step("property", *args)
-        return self
-
-    def propertyMap(self, *args):
-        self.bytecode.add_step("propertyMap", *args)
-        return self
-
-    def range_(self, *args):
-        self.bytecode.add_step("range", *args)
-        return self
-
-    def read(self, *args):
-        self.bytecode.add_step("read", *args)
-        return self
-
-    def repeat(self, *args):
-        self.bytecode.add_step("repeat", *args)
-        return self
-
-    def sack(self, *args):
-        self.bytecode.add_step("sack", *args)
-        return self
-
-    def sample(self, *args):
-        self.bytecode.add_step("sample", *args)
-        return self
-
-    def select(self, *args):
-        self.bytecode.add_step("select", *args)
-        return self
-
-    def shortestPath(self, *args):
-        self.bytecode.add_step("shortestPath", *args)
-        return self
-
-    def sideEffect(self, *args):
-        self.bytecode.add_step("sideEffect", *args)
-        return self
-
-    def simplePath(self, *args):
-        self.bytecode.add_step("simplePath", *args)
-        return self
-
-    def skip(self, *args):
-        self.bytecode.add_step("skip", *args)
-        return self
-
-    def store(self, *args):
-        self.bytecode.add_step("store", *args)
-        return self
-
-    def subgraph(self, *args):
-        self.bytecode.add_step("subgraph", *args)
-        return self
-
-    def sum_(self, *args):
-        self.bytecode.add_step("sum", *args)
-        return self
-
-    def tail(self, *args):
-        self.bytecode.add_step("tail", *args)
-        return self
-
-    def timeLimit(self, *args):
-        self.bytecode.add_step("timeLimit", *args)
-        return self
-
-    def times(self, *args):
-        self.bytecode.add_step("times", *args)
-        return self
-
-    def to(self, *args):
-        self.bytecode.add_step("to", *args)
-        return self
-
-    def toE(self, *args):
-        self.bytecode.add_step("toE", *args)
-        return self
-
-    def toV(self, *args):
-        self.bytecode.add_step("toV", *args)
-        return self
-
-    def tree(self, *args):
-        self.bytecode.add_step("tree", *args)
-        return self
-
-    def unfold(self, *args):
-        self.bytecode.add_step("unfold", *args)
-        return self
-
-    def union(self, *args):
-        self.bytecode.add_step("union", *args)
-        return self
-
-    def until(self, *args):
-        self.bytecode.add_step("until", *args)
-        return self
-
-    def value(self, *args):
-        self.bytecode.add_step("value", *args)
-        return self
-
-    def valueMap(self, *args):
-        self.bytecode.add_step("valueMap", *args)
-        return self
-
-    def values(self, *args):
-        self.bytecode.add_step("values", *args)
-        return self
-
-    def where(self, *args):
-        self.bytecode.add_step("where", *args)
-        return self
-
-    def with_(self, *args):
-        self.bytecode.add_step("with", *args)
-        return self
-
-    def write(self, *args):
-        self.bytecode.add_step("write", *args)
-        return self
-
-    # Deprecated - prefer the underscore suffixed versions e.g filter_()
-
-    def filter(self, *args):
-        self.bytecode.add_step("filter", *args)
-        return self
-
-    def id(self, *args):
-        self.bytecode.add_step("id", *args)
-        return self
-
-    def max(self, *args):
-        self.bytecode.add_step("max", *args)
-        return self
-
-    def min(self, *args):
-        self.bytecode.add_step("min", *args)
-        return self
-
-    def range(self, *args):
-        self.bytecode.add_step("range", *args)
-        return self
-
-    def sum(self, *args):
-        self.bytecode.add_step("sum", *args)
-        return self
-
-class MagicType(type):
-
-    def __getattr__(cls, k):
-        if k.startswith('__'):
-            raise AttributeError(
-                'Python magic methods or keys starting with double underscore cannot be used for Gremlin sugar - prefer values(' + k + ')')
-        return __.values(k)
-
-class __(object):
-    __metaclass__ = MagicType
-    graph_traversal = GraphTraversal
-
-    @classmethod
-    def start(cls):
-        return GraphTraversal(None, None, Bytecode())
-
-    @classmethod
-    def __(cls, *args):
-        return __.inject(*args)
-
-    @classmethod
-    def V(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).V(*args)
-
-    @classmethod
-    def addE(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).addE(*args)
-
-    @classmethod
-    def addV(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).addV(*args)
-
-    @classmethod
-    def aggregate(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).aggregate(*args)
-
-    @classmethod
-    def and_(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).and_(*args)
-
-    @classmethod
-    def as_(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).as_(*args)
-
-    @classmethod
-    def barrier(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).barrier(*args)
-
-    @classmethod
-    def both(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).both(*args)
-
-    @classmethod
-    def bothE(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).bothE(*args)
-
-    @classmethod
-    def bothV(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).bothV(*args)
-
-    @classmethod
-    def branch(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).branch(*args)
-
-    @classmethod
-    def cap(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).cap(*args)
-
-    @classmethod
-    def choose(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).choose(*args)
-
-    @classmethod
-    def coalesce(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).coalesce(*args)
-
-    @classmethod
-    def coin(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).coin(*args)
-
-    @classmethod
-    def constant(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).constant(*args)
-
-    @classmethod
-    def count(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).count(*args)
-
-    @classmethod
-    def cyclicPath(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).cyclicPath(*args)
-
-    @classmethod
-    def dedup(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).dedup(*args)
-
-    @classmethod
-    def drop(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).drop(*args)
-
-    @classmethod
-    def elementMap(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).elementMap(*args)
-
-    @classmethod
-    def emit(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).emit(*args)
-
-    @classmethod
-    def filter_(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).filter_(*args)
-
-    @classmethod
-    def flatMap(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).flatMap(*args)
-
-    @classmethod
-    def fold(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).fold(*args)
-
-    @classmethod
-    def group(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).group(*args)
-
-    @classmethod
-    def groupCount(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).groupCount(*args)
-
-    @classmethod
-    def has(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).has(*args)
-
-    @classmethod
-    def hasId(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).hasId(*args)
-
-    @classmethod
-    def hasKey(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).hasKey(*args)
-
-    @classmethod
-    def hasLabel(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).hasLabel(*args)
-
-    @classmethod
-    def hasNot(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).hasNot(*args)
-
-    @classmethod
-    def hasValue(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).hasValue(*args)
-
-    @classmethod
-    def id_(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).id_(*args)
-
-    @classmethod
-    def identity(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).identity(*args)
-
-    @classmethod
-    def inE(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).inE(*args)
-
-    @classmethod
-    def inV(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).inV(*args)
-
-    @classmethod
-    def in_(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).in_(*args)
-
-    @classmethod
-    def index(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).index(*args)
-
-    @classmethod
-    def inject(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).inject(*args)
-
-    @classmethod
-    def is_(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).is_(*args)
-
-    @classmethod
-    def key(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).key(*args)
-
-    @classmethod
-    def label(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).label(*args)
-
-    @classmethod
-    def limit(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).limit(*args)
-
-    @classmethod
-    def local(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).local(*args)
-
-    @classmethod
-    def loops(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).loops(*args)
-
-    @classmethod
-    def map(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).map(*args)
-
-    @classmethod
-    def match(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).match(*args)
-
-    @classmethod
-    def math(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).math(*args)
-
-    @classmethod
-    def max_(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).max_(*args)
-
-    @classmethod
-    def mean(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).mean(*args)
-
-    @classmethod
-    def min_(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).min_(*args)
-
-    @classmethod
-    def not_(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).not_(*args)
-
-    @classmethod
-    def optional(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).optional(*args)
-
-    @classmethod
-    def or_(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).or_(*args)
-
-    @classmethod
-    def order(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).order(*args)
-
-    @classmethod
-    def otherV(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).otherV(*args)
-
-    @classmethod
-    def out(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).out(*args)
-
-    @classmethod
-    def outE(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).outE(*args)
-
-    @classmethod
-    def outV(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).outV(*args)
-
-    @classmethod
-    def path(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).path(*args)
-
-    @classmethod
-    def project(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).project(*args)
-
-    @classmethod
-    def properties(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).properties(*args)
-
-    @classmethod
-    def property(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).property(*args)
-
-    @classmethod
-    def propertyMap(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).propertyMap(*args)
-
-    @classmethod
-    def range_(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).range_(*args)
-
-    @classmethod
-    def repeat(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).repeat(*args)
-
-    @classmethod
-    def sack(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).sack(*args)
-
-    @classmethod
-    def sample(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).sample(*args)
-
-    @classmethod
-    def select(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).select(*args)
-
-    @classmethod
-    def sideEffect(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).sideEffect(*args)
-
-    @classmethod
-    def simplePath(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).simplePath(*args)
-
-    @classmethod
-    def skip(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).skip(*args)
-
-    @classmethod
-    def store(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).store(*args)
-
-    @classmethod
-    def subgraph(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).subgraph(*args)
-
-    @classmethod
-    def sum_(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).sum_(*args)
-
-    @classmethod
-    def tail(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).tail(*args)
-
-    @classmethod
-    def timeLimit(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).timeLimit(*args)
-
-    @classmethod
-    def times(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).times(*args)
-
-    @classmethod
-    def to(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).to(*args)
-
-    @classmethod
-    def toE(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).toE(*args)
-
-    @classmethod
-    def toV(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).toV(*args)
-
-    @classmethod
-    def tree(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).tree(*args)
-
-    @classmethod
-    def unfold(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).unfold(*args)
-
-    @classmethod
-    def union(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).union(*args)
-
-    @classmethod
-    def until(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).until(*args)
-
-    @classmethod
-    def value(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).value(*args)
-
-    @classmethod
-    def valueMap(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).valueMap(*args)
-
-    @classmethod
-    def values(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).values(*args)
-
-    @classmethod
-    def where(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).where(*args)
-
-    # Deprecated - prefer the underscore suffixed versions e.g filter_()
-
-    @classmethod
-    def filter(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).filter_(*args)
-
-    @classmethod
-    def id(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).id_(*args)
-
-    @classmethod
-    def max(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).max_(*args)
-
-    @classmethod
-    def min(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).min_(*args)
-
-    @classmethod
-    def range(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).range_(*args)
-
-    @classmethod
-    def sum(cls, *args):
-        return cls.graph_traversal(None, None, Bytecode()).sum_(*args)
-
-
-def V(*args):
-    return __.V(*args)
-
-
-def addE(*args):
-    return __.addE(*args)
-
-
-def addV(*args):
-    return __.addV(*args)
-
-
-def aggregate(*args):
-    return __.aggregate(*args)
-
-
-def and_(*args):
-    return __.and_(*args)
-
-
-def as_(*args):
-    return __.as_(*args)
-
-
-def barrier(*args):
-    return __.barrier(*args)
-
-
-def both(*args):
-    return __.both(*args)
-
-
-def bothE(*args):
-    return __.bothE(*args)
-
-
-def bothV(*args):
-    return __.bothV(*args)
-
-
-def branch(*args):
-    return __.branch(*args)
-
-
-def cap(*args):
-    return __.cap(*args)
-
-
-def choose(*args):
-    return __.choose(*args)
-
-
-def coalesce(*args):
-    return __.coalesce(*args)
-
-
-def coin(*args):
-    return __.coin(*args)
-
-
-def constant(*args):
-    return __.constant(*args)
-
-
-def count(*args):
-    return __.count(*args)
-
-
-def cyclicPath(*args):
-    return __.cyclicPath(*args)
-
-
-def dedup(*args):
-    return __.dedup(*args)
-
-
-def drop(*args):
-    return __.drop(*args)
-
-
-def elementMap(*args):
-    return __.elementMap(*args)
-
-
-def emit(*args):
-    return __.emit(*args)
-
-
-def filter_(*args):
-    return __.filter_(*args)
-
-
-def flatMap(*args):
-    return __.flatMap(*args)
-
-
-def fold(*args):
-    return __.fold(*args)
-
-
-def group(*args):
-    return __.group(*args)
-
-
-def groupCount(*args):
-    return __.groupCount(*args)
-
-
-def has(*args):
-    return __.has(*args)
-
-
-def hasId(*args):
-    return __.hasId(*args)
-
-
-def hasKey(*args):
-    return __.hasKey(*args)
-
-
-def hasLabel(*args):
-    return __.hasLabel(*args)
-
-
-def hasNot(*args):
-    return __.hasNot(*args)
-
-
-def hasValue(*args):
-    return __.hasValue(*args)
-
-
-def id_(*args):
-    return __.id_(*args)
-
-
-def identity(*args):
-    return __.identity(*args)
-
-
-def inE(*args):
-    return __.inE(*args)
-
-
-def inV(*args):
-    return __.inV(*args)
-
-
-def in_(*args):
-    return __.in_(*args)
-
-
-def index(*args):
-    return __.index(*args)
-
-
-def inject(*args):
-    return __.inject(*args)
-
-
-def is_(*args):
-    return __.is_(*args)
-
-
-def key(*args):
-    return __.key(*args)
-
-
-def label(*args):
-    return __.label(*args)
-
-
-def limit(*args):
-    return __.limit(*args)
-
-
-def local(*args):
-    return __.local(*args)
-
-
-def loops(*args):
-    return __.loops(*args)
-
-
-def map(*args):
-    return __.map(*args)
-
-
-def match(*args):
-    return __.match(*args)
-
-
-def math(*args):
-    return __.math(*args)
-
-
-def max_(*args):
-    return __.max_(*args)
-
-
-def mean(*args):
-    return __.mean(*args)
-
-
-def min_(*args):
-    return __.min_(*args)
-
-
-def not_(*args):
-    return __.not_(*args)
-
-
-def optional(*args):
-    return __.optional(*args)
-
-
-def or_(*args):
-    return __.or_(*args)
-
-
-def order(*args):
-    return __.order(*args)
-
-
-def otherV(*args):
-    return __.otherV(*args)
-
-
-def out(*args):
-    return __.out(*args)
-
-
-def outE(*args):
-    return __.outE(*args)
-
-
-def outV(*args):
-    return __.outV(*args)
-
-
-def path(*args):
-    return __.path(*args)
-
-
-def project(*args):
-    return __.project(*args)
-
-
-def properties(*args):
-    return __.properties(*args)
-
-
-def property(*args):
-    return __.property(*args)
-
-
-def propertyMap(*args):
-    return __.propertyMap(*args)
-
-
-def range_(*args):
-    return __.range_(*args)
-
-
-def repeat(*args):
-    return __.repeat(*args)
-
-
-def sack(*args):
-    return __.sack(*args)
-
-
-def sample(*args):
-    return __.sample(*args)
-
-
-def select(*args):
-    return __.select(*args)
-
-
-def sideEffect(*args):
-    return __.sideEffect(*args)
-
-
-def simplePath(*args):
-    return __.simplePath(*args)
-
-
-def skip(*args):
-    return __.skip(*args)
-
-
-def store(*args):
-    return __.store(*args)
-
-
-def subgraph(*args):
-    return __.subgraph(*args)
-
-
-def sum_(*args):
-    return __.sum_(*args)
-
-
-def tail(*args):
-    return __.tail(*args)
-
-
-def timeLimit(*args):
-    return __.timeLimit(*args)
-
-
-def times(*args):
-    return __.times(*args)
-
-
-def to(*args):
-    return __.to(*args)
-
-
-def toE(*args):
-    return __.toE(*args)
-
-
-def toV(*args):
-    return __.toV(*args)
-
-
-def tree(*args):
-    return __.tree(*args)
-
-
-def unfold(*args):
-    return __.unfold(*args)
-
-
-def union(*args):
-    return __.union(*args)
-
-
-def until(*args):
-    return __.until(*args)
-
-
-def value(*args):
-    return __.value(*args)
-
-
-def valueMap(*args):
-    return __.valueMap(*args)
-
-
-def values(*args):
-    return __.values(*args)
-
-
-def where(*args):
-    return __.where(*args)
-
-
-# Deprecated - prefer the underscore suffixed versions e.g filter_()
-
-def filter(*args):
-    return __.filter_(*args)
-
-
-def id(*args):
-    return __.id_(*args)
-
-
-def max(*args):
-    return __.max_(*args)
-
-
-def min(*args):
-    return __.min_(*args)
-
-
-def range(*args):
-    return __.range_(*args)
-
-
-def sum(*args):
-    return __.sum_(*args)
-
-
-statics.add_static('V', V)
-
-statics.add_static('addE', addE)
-
-statics.add_static('addV', addV)
-
-statics.add_static('aggregate', aggregate)
-
-statics.add_static('and_', and_)
-
-statics.add_static('as_', as_)
-
-statics.add_static('barrier', barrier)
-
-statics.add_static('both', both)
-
-statics.add_static('bothE', bothE)
-
-statics.add_static('bothV', bothV)
-
-statics.add_static('branch', branch)
-
-statics.add_static('cap', cap)
-
-statics.add_static('choose', choose)
-
-statics.add_static('coalesce', coalesce)
-
-statics.add_static('coin', coin)
-
-statics.add_static('constant', constant)
-
-statics.add_static('count', count)
-
-statics.add_static('cyclicPath', cyclicPath)
-
-statics.add_static('dedup', dedup)
-
-statics.add_static('drop', drop)
-
-statics.add_static('elementMap', elementMap)
-
-statics.add_static('emit', emit)
-
-statics.add_static('filter_', filter_)
-
-statics.add_static('flatMap', flatMap)
-
-statics.add_static('fold', fold)
-
-statics.add_static('group', group)
-
-statics.add_static('groupCount', groupCount)
-
-statics.add_static('has', has)
-
-statics.add_static('hasId', hasId)
-
-statics.add_static('hasKey', hasKey)
-
-statics.add_static('hasLabel', hasLabel)
-
-statics.add_static('hasNot', hasNot)
-
-statics.add_static('hasValue', hasValue)
-
-statics.add_static('id_', id_)
-
-statics.add_static('identity', identity)
-
-statics.add_static('inE', inE)
-
-statics.add_static('inV', inV)
-
-statics.add_static('in_', in_)
-
-statics.add_static('index', index)
-
-statics.add_static('inject', inject)
-
-statics.add_static('is_', is_)
-
-statics.add_static('key', key)
-
-statics.add_static('label', label)
-
-statics.add_static('limit', limit)
-
-statics.add_static('local', local)
-
-statics.add_static('loops', loops)
-
-statics.add_static('map', map)
-
-statics.add_static('match', match)
-
-statics.add_static('math', math)
-
-statics.add_static('max_', max_)
-
-statics.add_static('mean', mean)
-
-statics.add_static('min_', min_)
-
-statics.add_static('not_', not_)
-
-statics.add_static('optional', optional)
-
-statics.add_static('or_', or_)
-
-statics.add_static('order', order)
-
-statics.add_static('otherV', otherV)
-
-statics.add_static('out', out)
-
-statics.add_static('outE', outE)
-
-statics.add_static('outV', outV)
-
-statics.add_static('path', path)
-
-statics.add_static('project', project)
-
-statics.add_static('properties', properties)
-
-statics.add_static('property', property)
-
-statics.add_static('propertyMap', propertyMap)
-
-statics.add_static('range_', range_)
-
-statics.add_static('repeat', repeat)
-
-statics.add_static('sack', sack)
-
-statics.add_static('sample', sample)
-
-statics.add_static('select', select)
-
-statics.add_static('sideEffect', sideEffect)
-
-statics.add_static('simplePath', simplePath)
-
-statics.add_static('skip', skip)
-
-statics.add_static('store', store)
-
-statics.add_static('subgraph', subgraph)
-
-statics.add_static('sum_', sum_)
-
-statics.add_static('tail', tail)
-
-statics.add_static('timeLimit', timeLimit)
-
-statics.add_static('times', times)
-
-statics.add_static('to', to)
-
-statics.add_static('toE', toE)
-
-statics.add_static('toV', toV)
-
-statics.add_static('tree', tree)
-
-statics.add_static('unfold', unfold)
-
-statics.add_static('union', union)
-
-statics.add_static('until', until)
-
-statics.add_static('value', value)
-
-statics.add_static('valueMap', valueMap)
-
-statics.add_static('values', values)
-
-statics.add_static('where', where)
-
-
-# Deprecated - prefer the underscore suffixed versions e.g filter_()
-
-statics.add_static('filter', filter)
-statics.add_static('id', id)
-statics.add_static('max', max)
-statics.add_static('min', min)
-statics.add_static('range', range)
-statics.add_static('sum', sum)
diff --git a/gremlin-python/src/main/jython/gremlin_python/process/strategies.py b/gremlin-python/src/main/jython/gremlin_python/process/strategies.py
deleted file mode 100644
index a7b49a3..0000000
--- a/gremlin-python/src/main/jython/gremlin_python/process/strategies.py
+++ /dev/null
@@ -1,216 +0,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.
-#
-
-__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
-
-from gremlin_python.process.traversal import TraversalStrategy
-
-base_namespace = 'org.apache.tinkerpop.gremlin.process.traversal.strategy.'
-decoration_namespace = base_namespace + 'decoration.'
-finalization_namespace = base_namespace + 'finalization.'
-optimization_namespace = base_namespace + 'optimization.'
-verification_namespace = base_namespace + 'verification.'
-computer_decoration_namespace = 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.'
-
-#########################
-# DECORATION STRATEGIES #
-#########################
-
-
-class ConnectiveStrategy(TraversalStrategy):
-    def __init__(self):
-        TraversalStrategy.__init__(self, fqcn=decoration_namespace + 'ConnectiveStrategy')
-
-
-class ElementIdStrategy(TraversalStrategy):
-    def __init__(self):
-        TraversalStrategy.__init__(self, fqcn=decoration_namespace + 'ElementIdStrategy')
-
-
-# EventStrategy doesn't make sense outside JVM traversal machine
-
-class HaltedTraverserStrategy(TraversalStrategy):
-    def __init__(self, halted_traverser_factory=None):
-        TraversalStrategy.__init__(self, fqcn=decoration_namespace + 'HaltedTraverserStrategy')
-        if halted_traverser_factory is not None:
-            self.configuration["haltedTraverserFactory"] = halted_traverser_factory
-
-
-class OptionsStrategy(TraversalStrategy):
-    def __init__(self, options=None):
-        TraversalStrategy.__init__(self, configuration=options, fqcn=decoration_namespace + 'OptionsStrategy')
-
-
-class PartitionStrategy(TraversalStrategy):
-    def __init__(self, partition_key=None, write_partition=None, read_partitions=None, include_meta_properties=None):
-        TraversalStrategy.__init__(self, fqcn=decoration_namespace + 'PartitionStrategy')
-        if partition_key is not None:
-            self.configuration["partitionKey"] = partition_key
-        if write_partition is not None:
-            self.configuration["writePartition"] = write_partition
-        if read_partitions is not None:
-            self.configuration["readPartitions"] = read_partitions
-        if include_meta_properties is not None:
-            self.configuration["includeMetaProperties"] = include_meta_properties
-
-
-class SubgraphStrategy(TraversalStrategy):
-
-    def __init__(self, vertices=None, edges=None, vertex_properties=None):
-        TraversalStrategy.__init__(self, fqcn=decoration_namespace + 'SubgraphStrategy')
-        if vertices is not None:
-            self.configuration["vertices"] = vertices
-        if edges is not None:
-            self.configuration["edges"] = edges
-        if vertex_properties is not None:
-            self.configuration["vertexProperties"] = vertex_properties
-
-
-class VertexProgramStrategy(TraversalStrategy):
-    def __init__(self, graph_computer=None, workers=None, persist=None, result=None, vertices=None, edges=None,
-                 configuration=None):
-        TraversalStrategy.__init__(self, fqcn=computer_decoration_namespace + 'VertexProgramStrategy')
-        if graph_computer is not None:
-            self.configuration["graphComputer"] = graph_computer
-        if workers is not None:
-            self.configuration["workers"] = workers
-        if persist is not None:
-            self.configuration["persist"] = persist
-        if result is not None:
-            self.configuration["result"] = result
-        if vertices is not None:
-            self.configuration["vertices"] = vertices
-        if edges is not None:
-            self.configuration["edges"] = edges
-        if configuration is not None:
-            self.configuration.update(configuration)
-
-
-###########################
-# FINALIZATION STRATEGIES #
-###########################
-
-class MatchAlgorithmStrategy(TraversalStrategy):
-    def __init__(self, match_algorithm=None):
-        TraversalStrategy.__init__(self, fqcn=finalization_namespace + 'MatchAlgorithmStrategy')
-        if match_algorithm is not None:
-            self.configuration["matchAlgorithm"] = match_algorithm
-
-
-###########################
-# OPTIMIZATION STRATEGIES #
-###########################
-
-class AdjacentToIncidentStrategy(TraversalStrategy):
-    def __init__(self):
-        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'AdjacentToIncidentStrategy')
-
-
-class FilterRankingStrategy(TraversalStrategy):
-    def __init__(self):
-        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'FilterRankingStrategy')
-
-
-class IdentityRemovalStrategy(TraversalStrategy):
-    def __init__(self):
-        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'IdentityRemovalStrategy')
-
-
-class IncidentToAdjacentStrategy(TraversalStrategy):
-    def __init__(self):
-        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'IncidentToAdjacentStrategy')
-
-
-class InlineFilterStrategy(TraversalStrategy):
-    def __init__(self):
-        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'InlineFilterStrategy')
-
-
-class LazyBarrierStrategy(TraversalStrategy):
-    def __init__(self):
-        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'LazyBarrierStrategy')
-
-
-class MatchPredicateStrategy(TraversalStrategy):
-    def __init__(self):
-        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'MatchPredicateStrategy')
-
-
-class OrderLimitStrategy(TraversalStrategy):
-    def __init__(self):
-        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'OrderLimitStrategy')
-
-
-class PathProcessorStrategy(TraversalStrategy):
-    def __init__(self):
-        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'PathProcessorStrategy')
-
-
-class PathRetractionStrategy(TraversalStrategy):
-    def __init__(self):
-        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'PathRetractionStrategy')
-
-
-class CountStrategy(TraversalStrategy):
-    def __init__(self):
-        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'CountStrategy')
-
-
-class RepeatUnrollStrategy(TraversalStrategy):
-    def __init__(self):
-        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'RepeatUnrollStrategy')
-
-
-class GraphFilterStrategy(TraversalStrategy):
-    def __init__(self):
-        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'GraphFilterStrategy')
-
-
-
-class EarlyLimitStrategy(TraversalStrategy):
-    def __init__(self):
-        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'EarlyLimitStrategy')
-
-###########################
-# VERIFICATION STRATEGIES #
-###########################
-
-
-class LambdaRestrictionStrategy(TraversalStrategy):
-    def __init__(self):
-        TraversalStrategy.__init__(self, fqcn=verification_namespace + 'LambdaRestrictionStrategy')
-
-class ReadOnlyStrategy(TraversalStrategy):
-    def __init__(self):
-        TraversalStrategy.__init__(self, fqcn=verification_namespace + 'ReadOnlyStrategy')
-
-
-class EdgeLabelVerificationStrategy(TraversalStrategy):
-    def __init__(self, log_warning=False, throw_exception=False):
-        TraversalStrategy.__init__(self, fqcn=verification_namespace + 'EdgeLabelVerificationStrategy')
-        self.configuration["logWarning"] = log_warning
-        self.configuration["throwException"] = throw_exception
-
-
-class ReservedKeysVerificationStrategy(TraversalStrategy):
-    def __init__(self, log_warning=False, throw_exception=False, keys=["id", "label"]):
-        TraversalStrategy.__init__(self, fqcn=verification_namespace + 'ReservedKeysVerificationStrategy')
-        self.configuration["logWarning"] = log_warning
-        self.configuration["throwException"] = throw_exception
-        self.configuration["keys"] = keys
diff --git a/gremlin-python/src/main/jython/gremlin_python/process/traversal.py b/gremlin-python/src/main/jython/gremlin_python/process/traversal.py
deleted file mode 100644
index ff0d121..0000000
--- a/gremlin-python/src/main/jython/gremlin_python/process/traversal.py
+++ /dev/null
@@ -1,736 +0,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.
-#
-
-import copy
-from aenum import Enum
-from .. import statics
-from ..statics import long
-
-class Traversal(object):
-    def __init__(self, graph, traversal_strategies, bytecode):
-        self.graph = graph
-        self.traversal_strategies = traversal_strategies
-        self.bytecode = bytecode
-        self.side_effects = TraversalSideEffects()
-        self.traversers = None
-        self.last_traverser = None
-
-    def __repr__(self):
-        return str(self.bytecode)
-
-    def __eq__(self, other):
-        if isinstance(other, self.__class__):
-            return self.bytecode == other.bytecode
-        else:
-            return False
-
-    def __iter__(self):
-        return self
-
-    def __next__(self):
-        if self.traversers is None:
-            self.traversal_strategies.apply_strategies(self)
-        if self.last_traverser is None:
-            self.last_traverser = next(self.traversers)
-        object = self.last_traverser.object
-        self.last_traverser.bulk = self.last_traverser.bulk - 1
-        if self.last_traverser.bulk <= 0:
-            self.last_traverser = None
-        return object
-
-    def toList(self):
-        return list(iter(self))
-
-    def toSet(self):
-        return set(iter(self))
-
-    def iterate(self):
-        self.bytecode.add_step("none")
-        while True:
-            try: self.nextTraverser()
-            except StopIteration: return self
-
-    def nextTraverser(self):
-        if self.traversers is None:
-            self.traversal_strategies.apply_strategies(self)
-        if self.last_traverser is None:
-            return next(self.traversers)
-        else:
-            temp = self.last_traverser
-            self.last_traverser = None
-            return temp
-
-    def hasNext(self):
-        if self.traversers is None:
-            self.traversal_strategies.apply_strategies(self)
-        if self.last_traverser is None:
-            try: self.last_traverser = next(self.traversers)
-            except StopIteration: return False
-        return not(self.last_traverser is None) and self.last_traverser.bulk > 0
-
-    def next(self, amount=None):
-        if amount is None:
-            return self.__next__()
-        else:
-            count = 0
-            tempList = []
-            while count < amount:
-                count = count + 1
-                try: temp = self.__next__()
-                except StopIteration: return tempList
-                tempList.append(temp)
-            return tempList
-
-    def promise(self, cb=None):
-        self.traversal_strategies.apply_async_strategies(self)
-        future_traversal = self.remote_results
-        future = type(future_traversal)()
-        def process(f):
-            try:
-                traversal = f.result()
-            except Exception as e:
-                future.set_exception(e)
-            else:
-                self.traversers = iter(traversal.traversers)
-                self.side_effects = traversal.side_effects
-                if cb:
-                    try:
-                        result = cb(self)
-                    except Exception as e:
-                        future.set_exception(e)
-                    else:
-                        future.set_result(result)
-                else:
-                    future.set_result(self)
-        future_traversal.add_done_callback(process)
-        return future
-
-
-Barrier = Enum('Barrier', ' normSack')
-
-statics.add_static('normSack', Barrier.normSack)
-
-Cardinality = Enum('Cardinality', ' list_ set_ single')
-
-statics.add_static('single', Cardinality.single)
-statics.add_static('list_', Cardinality.list_)
-statics.add_static('set_', Cardinality.set_)
-
-Column = Enum('Column', ' keys values')
-
-statics.add_static('keys', Column.keys)
-statics.add_static('values', Column.values)
-
-Direction = Enum('Direction', ' BOTH IN OUT')
-
-statics.add_static('OUT', Direction.OUT)
-statics.add_static('IN', Direction.IN)
-statics.add_static('BOTH', Direction.BOTH)
-
-GraphSONVersion = Enum('GraphSONVersion', ' V1_0 V2_0 V3_0')
-
-statics.add_static('V1_0', GraphSONVersion.V1_0)
-statics.add_static('V2_0', GraphSONVersion.V2_0)
-statics.add_static('V3_0', GraphSONVersion.V3_0)
-
-GryoVersion = Enum('GryoVersion', ' V1_0 V3_0')
-
-statics.add_static('V1_0', GryoVersion.V1_0)
-statics.add_static('V3_0', GryoVersion.V3_0)
-
-Order = Enum('Order', ' asc decr desc incr shuffle')
-
-statics.add_static('incr', Order.incr)
-statics.add_static('decr', Order.decr)
-statics.add_static('shuffle', Order.shuffle)
-statics.add_static('asc', Order.asc)
-statics.add_static('desc', Order.desc)
-
-Pick = Enum('Pick', ' any none')
-
-statics.add_static('any', Pick.any)
-statics.add_static('none', Pick.none)
-
-Pop = Enum('Pop', ' all_ first last mixed')
-
-statics.add_static('first', Pop.first)
-statics.add_static('last', Pop.last)
-statics.add_static('all_', Pop.all_)
-statics.add_static('mixed', Pop.mixed)
-
-Scope = Enum('Scope', ' global_ local')
-
-statics.add_static('global_', Scope.global_)
-statics.add_static('local', Scope.local)
-
-
-T = Enum('T', ' id id_ key label value')
-
-statics.add_static('id', T.id)
-statics.add_static('label', T.label)
-statics.add_static('id_', T.id_)
-statics.add_static('key', T.key)
-statics.add_static('value', T.value)
-
-
-Operator = Enum('Operator', ' addAll and_ assign div max max_ min min_ minus mult or_ sum sum_ sumLong')
-
-statics.add_static('sum_', Operator.sum_)
-statics.add_static('sum', Operator.sum_)
-statics.add_static('minus', Operator.minus)
-statics.add_static('mult', Operator.mult)
-statics.add_static('div', Operator.div)
-statics.add_static('min', Operator.min_)
-statics.add_static('min_', Operator.min_)
-statics.add_static('max_', Operator.max_)
-statics.add_static('assign', Operator.assign)
-statics.add_static('and_', Operator.and_)
-statics.add_static('or_', Operator.or_)
-statics.add_static('addAll', Operator.addAll)
-statics.add_static('sumLong', Operator.sumLong)
-
-
-class P(object):
-    def __init__(self, operator, value, other=None):
-        self.operator = operator
-        self.value = value
-        self.other = other
-
-    @staticmethod
-    def between(*args):
-        return P("between", *args)
-
-    @staticmethod
-    def eq(*args):
-        return P("eq", *args)
-
-    @staticmethod
-    def gt(*args):
-        return P("gt", *args)
-
-    @staticmethod
-    def gte(*args):
-        return P("gte", *args)
-
-    @staticmethod
-    def inside(*args):
-        return P("inside", *args)
-
-    @staticmethod
-    def lt(*args):
-        return P("lt", *args)
-
-    @staticmethod
-    def lte(*args):
-        return P("lte", *args)
-
-    @staticmethod
-    def neq(*args):
-        return P("neq", *args)
-
-    @staticmethod
-    def not_(*args):
-        return P("not", *args)
-
-    @staticmethod
-    def outside(*args):
-        return P("outside", *args)
-
-    @staticmethod
-    def test(*args):
-        return P("test", *args)
-
-    @staticmethod
-    def within(*args):
-        if len(args) == 1 and type(args[0]) == list:
-            return P("within", args[0])
-        else:
-            return P("within", list(args))
-        
-    @staticmethod
-    def without(*args):
-        if len(args) == 1 and type(args[0]) == list:
-            return P("without", args[0])
-        else:
-            return P("without", list(args))
-
-    def and_(self, arg):
-        return P("and", self, arg)
-
-    def or_(self, arg):
-        return P("or", self, arg)
-
-    def __eq__(self, other):
-        return isinstance(other, self.__class__) and self.operator == other.operator and self.value == other.value and self.other == other.other
-
-    def __repr__(self):
-        return self.operator + "(" + str(self.value) + ")" if self.other is None else self.operator + "(" + str(self.value) + "," + str(self.other) + ")"
-
-
-def between(*args):
-    return P.between(*args)
-
-
-def eq(*args):
-    return P.eq(*args)
-
-
-def gt(*args):
-    return P.gt(*args)
-
-
-def gte(*args):
-    return P.gte(*args)
-
-
-def inside(*args):
-    return P.inside(*args)
-
-
-def lt(*args):
-    return P.lt(*args)
-
-
-def lte(*args):
-    return P.lte(*args)
-
-
-def neq(*args):
-    return P.neq(*args)
-
-
-def not_(*args):
-    return P.not_(*args)
-
-
-def outside(*args):
-    return P.outside(*args)
-
-
-def test(*args):
-    return P.test(*args)
-
-
-def within(*args):
-    return P.within(*args)
-
-
-def without(*args):
-    return P.without(*args)
-
-
-statics.add_static('between', between)
-
-statics.add_static('eq', eq)
-
-statics.add_static('gt', gt)
-
-statics.add_static('gte', gte)
-
-statics.add_static('inside', inside)
-
-statics.add_static('lt', lt)
-
-statics.add_static('lte', lte)
-
-statics.add_static('neq', neq)
-
-statics.add_static('not_', not_)
-
-statics.add_static('outside', outside)
-
-statics.add_static('test', test)
-
-statics.add_static('within', within)
-
-statics.add_static('without', without)
-
-
-class TextP(P):
-    def __init__(self, operator, value, other=None):
-        P.__init__(self, operator, value, other)
-
-    @staticmethod
-    def containing(*args):
-        return TextP("containing", *args)
-
-    @staticmethod
-    def endingWith(*args):
-        return TextP("endingWith", *args)
-
-    @staticmethod
-    def notContaining(*args):
-        return TextP("notContaining", *args)
-
-    @staticmethod
-    def notEndingWith(*args):
-        return TextP("notEndingWith", *args)
-
-    @staticmethod
-    def notStartingWith(*args):
-        return TextP("notStartingWith", *args)
-
-    @staticmethod
-    def startingWith(*args):
-        return TextP("startingWith", *args)
-
-    def __eq__(self, other):
-        return isinstance(other, self.__class__) and self.operator == other.operator and self.value == other.value and self.other == other.other
-
-    def __repr__(self):
-        return self.operator + "(" + str(self.value) + ")" if self.other is None else self.operator + "(" + str(self.value) + "," + str(self.other) + ")"
-
-
-def containing(*args):
-    return TextP.containing(*args)
-
-
-def endingWith(*args):
-    return TextP.endingWith(*args)
-
-
-def notContaining(*args):
-    return TextP.notContaining(*args)
-
-
-def notEndingWith(*args):
-    return TextP.notEndingWith(*args)
-
-
-def notStartingWith(*args):
-    return TextP.notStartingWith(*args)
-
-
-def startingWith(*args):
-    return TextP.startingWith(*args)
-
-
-statics.add_static('containing', containing)
-
-statics.add_static('endingWith', endingWith)
-
-statics.add_static('notContaining', notContaining)
-
-statics.add_static('notEndingWith', notEndingWith)
-
-statics.add_static('notStartingWith', notStartingWith)
-
-statics.add_static('startingWith', startingWith)
-
-
-
-
-'''
-IO
-'''
-
-
-class IO(object):
-
-    graphml = "graphml"
-
-    graphson = "graphson"
-
-    gryo = "gryo"
-
-    reader = "~tinkerpop.io.reader"
-
-    registry = "~tinkerpop.io.registry"
-
-    writer = "~tinkerpop.io.writer"
-
-
-'''
-ConnectedComponent
-'''
-
-
-class ConnectedComponent(object):
-
-    component = "gremlin.connectedComponentVertexProgram.component"
-
-    edges = "~tinkerpop.connectedComponent.edges"
-
-    propertyName = "~tinkerpop.connectedComponent.propertyName"
-
-
-'''
-ShortestPath
-'''
-
-
-class ShortestPath(object):
-
-    distance = "~tinkerpop.shortestPath.distance"
-
-    edges = "~tinkerpop.shortestPath.edges"
-
-    includeEdges = "~tinkerpop.shortestPath.includeEdges"
-
-    maxDistance = "~tinkerpop.shortestPath.maxDistance"
-
-    target = "~tinkerpop.shortestPath.target"
-
-
-'''
-PageRank
-'''
-
-
-class PageRank(object):
-
-    edges = "~tinkerpop.pageRank.edges"
-
-    propertyName = "~tinkerpop.pageRank.propertyName"
-
-    times = "~tinkerpop.pageRank.times"
-
-
-'''
-PeerPressure
-'''
-
-
-class PeerPressure(object):
-
-    edges = "~tinkerpop.peerPressure.edges"
-
-    propertyName = "~tinkerpop.peerPressure.propertyName"
-
-    times = "~tinkerpop.peerPressure.times"
-
-
-'''
-TRAVERSER
-'''
-
-
-class Traverser(object):
-    def __init__(self, object, bulk=None):
-        if bulk is None:
-            bulk = long(1)
-        self.object = object
-        self.bulk = bulk
-
-    def __repr__(self):
-        return str(self.object)
-
-    def __eq__(self, other):
-        return isinstance(other, self.__class__) and self.object == other.object
-
-
-'''
-TRAVERSAL SIDE-EFFECTS
-'''
-
-
-class TraversalSideEffects(object):
-    def keys(self):
-        return set()
-
-    def get(self, key):
-        raise KeyError(key)
-
-    def __getitem__(self, key):
-        return self.get(key)
-
-    def __repr__(self):
-        return "sideEffects[size:" + str(len(self.keys())) + "]"
-
-
-'''
-TRAVERSAL STRATEGIES
-'''
-
-
-class TraversalStrategies(object):
-    global_cache = {}
-
-    def __init__(self, traversal_strategies=None):
-        self.traversal_strategies =             traversal_strategies.traversal_strategies if traversal_strategies is not None else []
-
-    def add_strategies(self, traversal_strategies):
-        self.traversal_strategies = self.traversal_strategies + traversal_strategies
-
-    def apply_strategies(self, traversal):
-        for traversal_strategy in self.traversal_strategies:
-            traversal_strategy.apply(traversal)
-
-    def apply_async_strategies(self, traversal):
-        for traversal_strategy in self.traversal_strategies:
-            traversal_strategy.apply_async(traversal)
-
-    def __repr__(self):
-        return str(self.traversal_strategies)
-
-
-class TraversalStrategy(object):
-    def __init__(self, strategy_name=None, configuration=None, fqcn=None):
-        self.fqcn = fqcn
-        self.strategy_name = type(self).__name__ if strategy_name is None else strategy_name
-        self.configuration = {} if configuration is None else configuration
-
-    def apply(self, traversal):
-        return
-
-    def apply_async(self, traversal):
-        return
-
-    def __eq__(self, other):
-        return isinstance(other, self.__class__)
-
-    def __hash__(self):
-        return hash(self.strategy_name)
-
-    def __repr__(self):
-        return self.strategy_name
-
-
-'''
-BYTECODE
-'''
-
-
-class Bytecode(object):
-    def __init__(self, bytecode=None):
-        self.source_instructions = []
-        self.step_instructions = []
-        self.bindings = {}
-        if bytecode is not None:
-            self.source_instructions = list(bytecode.source_instructions)
-            self.step_instructions = list(bytecode.step_instructions)
-
-    def add_source(self, source_name, *args):
-        instruction = [source_name]
-        for arg in args:
-            instruction.append(self.__convertArgument(arg))
-        self.source_instructions.append(instruction)
-
-    def add_step(self, step_name, *args):
-        instruction = [step_name]
-        for arg in args:
-            instruction.append(self.__convertArgument(arg))
-        self.step_instructions.append(instruction)
-
-    def __eq__(self, other):
-        if isinstance(other, self.__class__):
-            return self.source_instructions == other.source_instructions and self.step_instructions == other.step_instructions
-        else:
-            return False
-
-    def __copy__(self):
-        bb = Bytecode()
-        bb.source_instructions = self.source_instructions
-        bb.step_instructions = self.step_instructions
-        bb.bindings = self.bindings
-        return bb
-
-    def __deepcopy__(self, memo={}):
-        bb = Bytecode()
-        bb.source_instructions = copy.deepcopy(self.source_instructions, memo)
-        bb.step_instructions = copy.deepcopy(self.step_instructions, memo)
-        bb.bindings = copy.deepcopy(self.bindings, memo)
-        return bb
-
-    def __convertArgument(self,arg):
-        if isinstance(arg, Traversal):
-            self.bindings.update(arg.bytecode.bindings)
-            return arg.bytecode
-        elif isinstance(arg, dict):
-            newDict = {}
-            for key in arg:
-                newDict[self.__convertArgument(key)] = self.__convertArgument(arg[key])
-            return newDict
-        elif isinstance(arg, list):
-            newList = []
-            for item in arg:
-                newList.append(self.__convertArgument(item))
-            return newList
-        elif isinstance(arg, set):
-            newSet = set()
-            for item in arg:
-                newSet.add(self.__convertArgument(item))
-            return newSet
-        elif isinstance(arg, Binding):
-            self.bindings[arg.key] = arg.value
-            return Binding(arg.key, self.__convertArgument(arg.value))
-        else:
-            return arg
-
-    def __repr__(self):
-        return (str(self.source_instructions) if len(self.source_instructions) > 0 else "") + \
-               (str(self.step_instructions) if len(self.step_instructions) > 0 else "")
-
-
-'''
-BINDINGS
-'''
-
-
-class Bindings(object):
-
-    @staticmethod
-    def of(key, value):
-        if not isinstance(key, str):
-            raise TypeError("Key must be str")
-        return Binding(key, value)
-
-
-class Binding(object):
-    def __init__(self, key, value):
-        self.key = key
-        self.value = value
-
-    def __eq__(self, other):
-        return isinstance(other, self.__class__) and self.key == other.key and self.value == other.value
-
-    def __hash__(self):
-        return hash(self.key) + hash(self.value)
-
-    def __repr__(self):
-        return "binding[" + self.key + "=" + str(self.value) + "]"
-
-
-'''
-WITH OPTIONS
-'''
-
-
-class WithOptions(object):
-
-    tokens = "~tinkerpop.valueMap.tokens"
-
-    none = 0
-
-    ids = 1
-
-    labels = 2
-
-    keys = 4
-
-    values = 8
-
-    all = 15
-
-    indexer = "~tinkerpop.index.indexer"
-
-    list = 0
-
-    map = 1
-
diff --git a/gremlin-python/src/main/jython/gremlin_python/statics.py b/gremlin-python/src/main/jython/gremlin_python/statics.py
deleted file mode 100644
index 221e166..0000000
--- a/gremlin-python/src/main/jython/gremlin_python/statics.py
+++ /dev/null
@@ -1,112 +0,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.
-#
-
-from types import FunctionType
-
-import six
-from aenum import Enum
-
-
-if six.PY3:
-    class long(int): pass
-    FloatType = float
-    IntType = int
-    LongType = long
-    TypeType = type
-    ListType = list
-    DictType = dict
-    SetType = set
-    ByteBufferType = bytes
-else:
-    long = long
-    SetType = set
-    ByteBufferType = bytearray
-    from types import FloatType
-    from types import IntType
-    from types import LongType
-    from types import TypeType
-    from types import ListType
-    from types import DictType
-    from types import TypeType
-
-
-class timestamp(float):
-    """
-    In Python a timestamp is simply a float. This dummy class (similar to long), allows users to wrap a float
-    in a GLV script to make sure the value is serialized as a Gremlin timestamp.
-    """
-    pass
-
-
-class SingleByte(int):
-    """
-    Provides a way to pass a single byte via Gremlin.
-    """
-    def __new__(cls, b):
-        if -128 <= b < 128:
-            int.__new__(cls, b)
-        else:
-            raise ValueError("value must be between -128 and 127 inclusive")
-
-
-class SingleChar(str):
-    """
-    Provides a way to pass a single character via Gremlin.
-    """
-    def __new__(cls, c):
-        if len(b) == 1:
-            str.__new__(cls, c)
-        else:
-            raise ValueError("string must contain a single character")
-
-
-class GremlinType(object):
-    """
-    Provides a way to represent a "Java class" for Gremlin.
-    """
-    def __init__(self, gremlin_type):
-        self.gremlin_type = gremlin_type
-        
-
-staticMethods = {}
-staticEnums = {}
-default_lambda_language = "gremlin-python"
-
-
-def add_static(key, value):
-    if isinstance(value, Enum):
-        staticEnums[key] = value
-    else:
-        staticMethods[key] = value
-
-
-def load_statics(global_dict):
-    for key in staticMethods:
-        global_dict[key] = staticMethods[key]
-    for key in staticEnums:
-        global_dict[key] = staticEnums[key]
-
-
-def unload_statics(global_dict):
-    for key in staticMethods:
-        if key in global_dict:
-            del global_dict[key]
-    for key in staticEnums:
-        if key in global_dict:
-            del global_dict[key]
diff --git a/gremlin-python/src/main/jython/gremlin_python/structure/io/graphbinaryV1.py b/gremlin-python/src/main/jython/gremlin_python/structure/io/graphbinaryV1.py
deleted file mode 100644
index c06ee12..0000000
--- a/gremlin-python/src/main/jython/gremlin_python/structure/io/graphbinaryV1.py
+++ /dev/null
@@ -1,1083 +0,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.
-"""
-
-import six
-import datetime
-import calendar
-import uuid
-import math
-import io
-import struct
-from collections import OrderedDict
-import logging
-
-from struct import pack, unpack
-from aenum import Enum
-from datetime import timedelta
-from gremlin_python import statics
-from gremlin_python.statics import FloatType, FunctionType, IntType, LongType, TypeType, DictType, ListType, SetType, \
-                                   SingleByte, ByteBufferType, GremlinType, SingleChar
-from gremlin_python.process.traversal import Barrier, Binding, Bytecode, Cardinality, Column, Direction, Operator, \
-                                             Order, Pick, Pop, P, Scope, TextP, Traversal, Traverser, \
-                                             TraversalStrategy, T
-from gremlin_python.process.graph_traversal import GraphTraversal
-from gremlin_python.structure.graph import Graph, Edge, Property, Vertex, VertexProperty, Path
-
-log = logging.getLogger(__name__)
-
-# When we fall back to a superclass's serializer, we iterate over this map.
-# We want that iteration order to be consistent, so we use an OrderedDict,
-# not a dict.
-_serializers = OrderedDict()
-_deserializers = {}
-
-
-class DataType(Enum):
-    null = 0xfe
-    int = 0x01
-    long = 0x02
-    string = 0x03
-    date = 0x04
-    timestamp = 0x05
-    clazz = 0x06
-    double = 0x07
-    float = 0x08
-    list = 0x09
-    map = 0x0a
-    set = 0x0b
-    uuid = 0x0c
-    edge = 0x0d
-    path = 0x0e
-    property = 0x0f
-    graph = 0x10                  # not supported - no graph object in python yet
-    vertex = 0x11
-    vertexproperty = 0x12
-    barrier = 0x13
-    binding = 0x14
-    bytecode = 0x15
-    cardinality = 0x16
-    column = 0x17
-    direction = 0x18
-    operator = 0x19
-    order = 0x1a
-    pick = 0x1b
-    pop = 0x1c
-    lambda_ = 0x1d
-    p = 0x1e
-    scope = 0x1f
-    t = 0x20
-    traverser = 0x21
-    bigdecimal = 0x22             # todo
-    biginteger = 0x23             # todo
-    byte = 0x24
-    bytebuffer = 0x25
-    short = 0x26                  # todo
-    boolean = 0x27
-    textp = 0x28
-    traversalstrategy = 0x29
-    bulkset = 0x2a
-    tree = 0x2b                   # not supported - no tree object in Python yet
-    metrics = 0x2c
-    traversalmetrics = 0x2d
-    char = 0x80
-    duration = 0x81
-    inetaddress = 0x82            # todo
-    instant = 0x83                # todo
-    localdate = 0x84              # todo
-    localdatetime = 0x85          # todo
-    localtime = 0x86              # todo
-    monthday = 0x87               # todo
-    offsetdatetime = 0x88         # todo
-    offsettime = 0x89             # todo
-    period = 0x8a                 # todo
-    year = 0x8b                   # todo
-    yearmonth = 0x8c              # todo
-    zonedatetime = 0x8d           # todo
-    zoneoffset = 0x8e             # todo
-    custom = 0x00                 # todo
-
-
-NULL_BYTES = [DataType.null.value, 0x01]
-
-
-def _make_packer(format_string):
-    packer = struct.Struct(format_string)
-    pack = packer.pack
-    unpack = lambda s: packer.unpack(s)[0]
-    return pack, unpack
-
-
-int64_pack, int64_unpack = _make_packer('>q')
-int32_pack, int32_unpack = _make_packer('>i')
-int8_pack, int8_unpack = _make_packer('>b')
-uint64_pack, uint64_unpack = _make_packer('>Q')
-uint8_pack, uint8_unpack = _make_packer('>B')
-float_pack, float_unpack = _make_packer('>f')
-double_pack, double_unpack = _make_packer('>d')
-
-
-class GraphBinaryTypeType(type):
-    def __new__(mcs, name, bases, dct):
-        cls = super(GraphBinaryTypeType, mcs).__new__(mcs, name, bases, dct)
-        if not name.startswith('_'):
-            if cls.python_type:
-                _serializers[cls.python_type] = cls
-            if cls.graphbinary_type:
-                _deserializers[cls.graphbinary_type] = cls
-        return cls
-
-
-class GraphBinaryWriter(object):
-    def __init__(self, serializer_map=None):
-        self.serializers = _serializers.copy()
-        if serializer_map:
-            self.serializers.update(serializer_map)
-
-    def writeObject(self, objectData):
-        return self.toDict(objectData)
-
-    def toDict(self, obj, to_extend=None):
-        if to_extend is None:
-            to_extend = bytearray()
-
-        try:
-            t = type(obj)
-            
-            # coerce unicode to str so the serializer will be found properly in the cache...better way?
-            if not six.PY3:
-                t = str if isinstance(obj, unicode) else t
-            return self.serializers[t].dictify(obj, self, to_extend)
-        except KeyError:
-            for key, serializer in self.serializers.items():
-                if isinstance(obj, key):
-                    return serializer.dictify(obj, self, to_extend)
-
-        if isinstance(obj, dict):
-            return dict((self.toDict(k, to_extend), self.toDict(v, to_extend)) for k, v in obj.items())
-        elif isinstance(obj, set):
-            return set([self.toDict(o, to_extend) for o in obj])
-        elif isinstance(obj, list):
-            return [self.toDict(o, to_extend) for o in obj]
-        else:
-            return obj
-
-
-class GraphBinaryReader(object):
-    def __init__(self, deserializer_map=None):
-        self.deserializers = _deserializers.copy()
-        if deserializer_map:
-            self.deserializers.update(deserializer_map)
-
-    def readObject(self, b):
-        if isinstance(b, bytearray):
-            return self.toObject(io.BytesIO(b))
-        elif isinstance(b, io.BufferedIOBase):
-            return self.toObject(b)
-
-    def toObject(self, buff, data_type=None, nullable=True):
-        if data_type is None:
-            bt = uint8_unpack(buff.read(1))
-            if bt == DataType.null.value:
-                if nullable:
-                    buff.read(1)
-                return None
-            return self.deserializers[DataType(bt)].objectify(buff, self, nullable)
-        else:
-            return self.deserializers[data_type].objectify(buff, self, nullable)
-
-
-@six.add_metaclass(GraphBinaryTypeType)
-class _GraphBinaryTypeIO(object):
-    python_type = None
-    graphbinary_type = None
-
-    symbolMap = {"global_": "global", "as_": "as", "in_": "in", "and_": "and",
-                 "or_": "or", "is_": "is", "not_": "not", "from_": "from",
-                 "set_": "set", "list_": "list", "all_": "all", "with_": "with",
-                 "filter_": "filter", "id_": "id", "max_": "max", "min_": "min", "sum_": "sum"}
-
-    @classmethod
-    def prefix_bytes(cls, graphbin_type, as_value=False, nullable=True, to_extend=None):
-        if to_extend is None:
-            to_extend = bytearray()
-
-        if not as_value:
-            to_extend += uint8_pack(graphbin_type.value)
-
-        if nullable:
-            to_extend += int8_pack(0)
-
-        return to_extend
-
-    @classmethod
-    def read_int(cls, buff):
-        return int32_unpack(buff.read(4))
-
-    @classmethod
-    def unmangle_keyword(cls, symbol):
-        return cls.symbolMap.get(symbol, symbol)
-
-    @classmethod
-    def is_null(cls, buff, reader, else_opt, nullable=True):
-        return None if nullable and buff.read(1)[0] == 0x01 else else_opt(buff, reader)
-
-    def dictify(self, obj, writer, to_extend, as_value=False, nullable=True):
-        raise NotImplementedError()
-
-    def objectify(self, d, reader, nullable=True):
-        raise NotImplementedError()
-        
-
-class LongIO(_GraphBinaryTypeIO):
-
-    python_type = LongType
-    graphbinary_type = DataType.long
-    byte_format_pack = int64_pack
-    byte_format_unpack = int64_unpack
-
-    @classmethod
-    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
-        if obj < -9223372036854775808 or obj > 9223372036854775807:
-            raise Exception("TODO: don't forget bigint")
-        else:
-            cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
-            to_extend.extend(cls.byte_format_pack(obj))
-            return to_extend
-
-    @classmethod
-    def objectify(cls, buff, reader, nullable=True):
-            return cls.is_null(buff, reader, lambda b, r: int64_unpack(buff.read(8)), nullable)
-
-
-class IntIO(LongIO):
-
-    python_type = IntType
-    graphbinary_type = DataType.int
-    byte_format_pack = int32_pack
-    byte_format_unpack = int32_unpack
-
-    @classmethod
-    def objectify(cls, buff, reader, nullable=True):
-        return cls.is_null(buff, reader, lambda b, r: cls.read_int(b), nullable)
-
-
-class DateIO(_GraphBinaryTypeIO):
-
-    python_type = datetime.datetime
-    graphbinary_type = DataType.date
-
-    @classmethod
-    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
-        try:
-            timestamp_seconds = calendar.timegm(obj.utctimetuple())
-            pts = timestamp_seconds * 1e3 + getattr(obj, 'microsecond', 0) / 1e3
-        except AttributeError:
-            pts = calendar.timegm(obj.timetuple()) * 1e3
-
-        ts = int(round(pts))
-        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
-        to_extend.extend(int64_pack(ts))
-        return to_extend
-
-    @classmethod
-    def objectify(cls, buff, reader, nullable=True):
-        return cls.is_null(buff, reader,
-                           lambda b, r: datetime.datetime.utcfromtimestamp(int64_unpack(b.read(8)) / 1000.0),
-                           nullable)
-
-
-# Based on current implementation, this class must always be declared before FloatIO.
-# Seems pretty fragile for future maintainers. Maybe look into this.
-class TimestampIO(_GraphBinaryTypeIO):
-    python_type = statics.timestamp
-    graphbinary_type = DataType.timestamp
-
-    @classmethod
-    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
-        # Java timestamp expects milliseconds integer - Have to use int because of legacy Python
-        ts = int(round(obj * 1000))
-        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
-        to_extend.extend(int64_pack(ts))
-        return to_extend
-
-    @classmethod
-    def objectify(cls, buff, reader, nullable=True):
-        # Python timestamp expects seconds
-        return cls.is_null(buff, reader, lambda b, r: statics.timestamp(int64_unpack(b.read(8)) / 1000.0),
-                           nullable)
-    
-
-def _long_bits_to_double(bits):
-    return unpack('d', pack('Q', bits))[0]
-
-
-NAN = _long_bits_to_double(0x7ff8000000000000)
-POSITIVE_INFINITY = _long_bits_to_double(0x7ff0000000000000)
-NEGATIVE_INFINITY = _long_bits_to_double(0xFff0000000000000)
-
-
-class FloatIO(LongIO):
-
-    python_type = FloatType
-    graphbinary_type = DataType.float
-    graphbinary_base_type = DataType.float
-    byte_format_pack = float_pack
-    byte_format_unpack = float_unpack
-
-    @classmethod
-    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
-        if math.isnan(obj):
-            cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
-            to_extend.extend(cls.byte_format_pack(NAN))
-        elif math.isinf(obj) and obj > 0:
-            cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
-            to_extend.extend(cls.byte_format_pack(POSITIVE_INFINITY))
-        elif math.isinf(obj) and obj < 0:
-            cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
-            to_extend.extend(cls.byte_format_pack(NEGATIVE_INFINITY))
-        else:
-            cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
-            to_extend.extend(cls.byte_format_pack(obj))
-
-        return to_extend
-
-    @classmethod
-    def objectify(cls, buff, reader, nullable=True):
-        return cls.is_null(buff, reader, lambda b, r: float_unpack(b.read(4)), nullable)
-
-
-class DoubleIO(FloatIO):
-    """
-    Floats basically just fall through to double serialization.
-    """
-
-    graphbinary_type = DataType.double
-    graphbinary_base_type = DataType.double
-    byte_format_pack = double_pack
-    byte_format_unpack = double_unpack
-
-    @classmethod
-    def objectify(cls, buff, reader, nullable=True):
-        return cls.is_null(buff, reader, lambda b, r: double_unpack(b.read(8)), nullable)
-
-
-class CharIO(_GraphBinaryTypeIO):
-    python_type = SingleChar
-    graphbinary_type = DataType.char
-
-    @classmethod
-    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
-        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
-        to_extend.extend(obj.encode("utf-8"))
-        return to_extend
-
-    @classmethod
-    def objectify(cls, buff, reader, nullable=True):
-        return cls.is_null(buff, reader, cls._read_char, nullable)
-
-    @classmethod
-    def _read_char(cls, b, r):
-        max_bytes = 4
-        x = b.read(1)
-        while max_bytes > 0:
-            max_bytes = max_bytes - 1
-            try:
-                return x.decode("utf-8")
-            except UnicodeDecodeError:
-                x += b.read(1)
-
-
-class StringIO(_GraphBinaryTypeIO):
-
-    python_type = str
-    graphbinary_type = DataType.string
-
-    @classmethod
-    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
-        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
-        str_bytes = obj.encode("utf-8")
-        to_extend += int32_pack(len(str_bytes))
-        to_extend += str_bytes
-        return to_extend
-
-    @classmethod
-    def objectify(cls, buff, reader, nullable=True):
-        return cls.is_null(buff, reader, lambda b, r: b.read(cls.read_int(b)).decode("utf-8"), nullable)
-
-
-class ListIO(_GraphBinaryTypeIO):
-
-    python_type = list
-    graphbinary_type = DataType.list
-
-    @classmethod
-    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
-        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
-        to_extend.extend(int32_pack(len(obj)))
-        for item in obj:
-            writer.toDict(item, to_extend)
-
-        return to_extend
-
-    @classmethod
-    def objectify(cls, buff, reader, nullable=True):
-        return cls.is_null(buff, reader, cls._read_list, nullable)
-
-    @classmethod
-    def _read_list(cls, b, r):
-        size = cls.read_int(b)
-        the_list = []
-        while size > 0:
-            the_list.append(r.readObject(b))
-            size = size - 1
-
-        return the_list
-
-
-class SetDeserializer(ListIO):
-
-    python_type = SetType
-    graphbinary_type = DataType.set
-
-    @classmethod
-    def objectify(cls, buff, reader, nullable=True):
-        return set(ListIO.objectify(buff, reader, nullable))
-
-
-class MapIO(_GraphBinaryTypeIO):
-
-    python_type = DictType
-    graphbinary_type = DataType.map
-
-    @classmethod
-    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
-        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
-
-        to_extend.extend(int32_pack(len(obj)))
-        for k, v in obj.items():
-            writer.toDict(k, to_extend)
-            writer.toDict(v, to_extend)
-
-        return to_extend
-
-    @classmethod
-    def objectify(cls, buff, reader, nullable=True):
-        return cls.is_null(buff, reader, cls._read_map, nullable)
-
-    @classmethod
-    def _read_map(cls, b, r):
-        size = cls.read_int(b)
-        the_dict = {}
-        while size > 0:
-            k = r.readObject(b)
-            v = r.readObject(b)
-            the_dict[k] = v
-            size = size - 1
-
-        return the_dict
-
-
-class UuidIO(_GraphBinaryTypeIO):
-
-    python_type = uuid.UUID
-    graphbinary_type = DataType.uuid
-
-    @classmethod
-    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
-        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
-        to_extend.extend(obj.bytes)
-        return to_extend
-
-    @classmethod
-    def objectify(cls, buff, reader, nullable=True):
-        return cls.is_null(buff, reader, lambda b, r: uuid.UUID(bytes=b.read(16)), nullable)
-
-
-class EdgeIO(_GraphBinaryTypeIO):
-
-    python_type = Edge
-    graphbinary_type = DataType.edge
-
-    @classmethod
-    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
-        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
-
-        writer.toDict(obj.id, to_extend)
-        StringIO.dictify(obj.label, writer, to_extend, True, False)
-        writer.toDict(obj.inV.id, to_extend)
-        StringIO.dictify(obj.inV.label, writer, to_extend, True, False)
-        writer.toDict(obj.outV.id, to_extend)
-        StringIO.dictify(obj.outV.label, writer, to_extend, True, False)
-        to_extend.extend(NULL_BYTES)
-        to_extend.extend(NULL_BYTES)
-
-        return to_extend
-
-    @classmethod
-    def objectify(cls, buff, reader, nullable=True):
-        return cls.is_null(buff, reader, cls._read_edge, nullable)
-
-    @classmethod
-    def _read_edge(cls, b, r):
-        edgeid = r.readObject(b)
-        edgelbl = r.toObject(b, DataType.string, False)
-        inv = Vertex(r.readObject(b), r.toObject(b, DataType.string, False))
-        outv = Vertex(r.readObject(b), r.toObject(b, DataType.string, False))
-        edge = Edge(edgeid, outv, edgelbl, inv)
-        b.read(4)
-        return edge
-
-
-class PathIO(_GraphBinaryTypeIO):
-
-    python_type = Path
-    graphbinary_type = DataType.path
-
-    @classmethod
-    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
-        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
-        writer.toDict(obj.labels, to_extend)
-        writer.toDict(obj.objects, to_extend)
-        return to_extend
-
-    @classmethod
-    def objectify(cls, buff, reader, nullable=True):
-        return cls.is_null(buff, reader, lambda b, r: Path(r.readObject(b), r.readObject(b)), nullable)
-
-
-class PropertyIO(_GraphBinaryTypeIO):
-
-    python_type = Property
-    graphbinary_type = DataType.property
-
-    @classmethod
-    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
-        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
-        StringIO.dictify(obj.key, writer, to_extend, True, False)
-        writer.toDict(obj.value, to_extend)
-        to_extend.extend(NULL_BYTES)
-        return to_extend
-
-    @classmethod
-    def objectify(cls, buff, reader, nullable=True):
-        return cls.is_null(buff, reader, cls._read_property, nullable)
-
-    @classmethod
-    def _read_property(cls, b, r):
-        p = Property(r.toObject(b, DataType.string, False), r.readObject(b), None)
-        b.read(2)
-        return p
-
-
-class TinkerGraphIO(_GraphBinaryTypeIO):
-
-    python_type = Graph
-    graphbinary_type = DataType.graph
-
-    @classmethod
-    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
-        raise AttributeError("TinkerGraph serialization is not currently supported by gremlin-python")
-
-    @classmethod
-    def objectify(cls, b, reader, as_value=False):
-        raise AttributeError("TinkerGraph deserialization is not currently supported by gremlin-python")
-
-
-class VertexIO(_GraphBinaryTypeIO):
-
-    python_type = Vertex
-    graphbinary_type = DataType.vertex
-
-    @classmethod
-    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
-        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
-        writer.toDict(obj.id, to_extend)
-        StringIO.dictify(obj.label, writer, to_extend, True, False)
-        to_extend.extend(NULL_BYTES)
-        return to_extend
-
-    @classmethod
-    def objectify(cls, buff, reader, nullable=True):
-        return cls.is_null(buff, reader, cls._read_vertex, nullable)
-
-    @classmethod
-    def _read_vertex(cls, b, r):
-        vertex = Vertex(r.readObject(b), r.toObject(b, DataType.string, False))
-        b.read(2)
-        return vertex
-
-
-class VertexPropertyIO(_GraphBinaryTypeIO):
-
-    python_type = VertexProperty
-    graphbinary_type = DataType.vertexproperty
-
-    @classmethod
-    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
-        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
-        writer.toDict(obj.id, to_extend)
-        StringIO.dictify(obj.label, writer, to_extend, True, False)
-        writer.toDict(obj.value, to_extend)
-        to_extend.extend(NULL_BYTES)
-        to_extend.extend(NULL_BYTES)
-        return to_extend
-
-    @classmethod
-    def objectify(cls, buff, reader, nullable=True):
-        return cls.is_null(buff, reader, cls._read_vertexproperty, nullable)
-
-    @classmethod
-    def _read_vertexproperty(cls, b, r):
-        vp = VertexProperty(r.readObject(b), r.toObject(b, DataType.string, False), r.readObject(b), None)
-        b.read(4)
-        return vp
-
-
-class _EnumIO(_GraphBinaryTypeIO):
-
-    @classmethod
-    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
-        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
-        StringIO.dictify(cls.unmangle_keyword(str(obj.name)), writer, to_extend)
-        return to_extend
-
-    @classmethod
-    def objectify(cls, buff, reader, nullable=True):
-        return cls.is_null(buff, reader, cls._read_enumval, nullable)
-
-    @classmethod
-    def _read_enumval(cls, b, r):
-        enum_name = r.toObject(b)
-        return cls.python_type[enum_name]
-
-
-class BarrierIO(_EnumIO):
-    graphbinary_type = DataType.barrier
-    python_type = Barrier
-
-
-class CardinalityIO(_EnumIO):
-    graphbinary_type = DataType.cardinality
-    python_type = Cardinality
-
-
-class ColumnIO(_EnumIO):
-    graphbinary_type = DataType.column
-    python_type = Column
-
-
-class DirectionIO(_EnumIO):
-    graphbinary_type = DataType.direction
-    python_type = Direction
-
-
-class OperatorIO(_EnumIO):
-    graphbinary_type = DataType.operator
-    python_type = Operator
-
-
-class OrderIO(_EnumIO):
-    graphbinary_type = DataType.order
-    python_type = Order
-
-
-class PickIO(_EnumIO):
-    graphbinary_type = DataType.pick
-    python_type = Pick
-
-
-class PopIO(_EnumIO):
-    graphbinary_type = DataType.pop
-    python_type = Pop
-
-
-class BindingIO(_GraphBinaryTypeIO):
-
-    python_type = Binding
-    graphbinary_type = DataType.binding
-
-    @classmethod
-    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
-        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
-        StringIO.dictify(obj.key, writer, to_extend, True, False)
-        writer.toDict(obj.value, to_extend)
-        return to_extend
-
-    @classmethod
-    def objectify(cls, buff, reader, nullable=True):
-        return cls.is_null(buff, reader, lambda b, r: Binding(r.toObject(b, DataType.string, False),
-                                                              reader.readObject(b)), nullable)
-
-
-class BytecodeIO(_GraphBinaryTypeIO):
-    python_type = Bytecode
-    graphbinary_type = DataType.bytecode
-
-    @classmethod
-    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
-        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
-        bc = obj.bytecode if isinstance(obj, Traversal) else obj
-        to_extend.extend(int32_pack(len(bc.step_instructions)))
-        for inst in bc.step_instructions:
-            inst_name, inst_args = inst[0], inst[1:] if len(inst) > 1 else []
-            StringIO.dictify(inst_name, writer, to_extend, True, False)
-            to_extend.extend(int32_pack(len(inst_args)))
-            for arg in inst_args:
-                writer.toDict(arg, to_extend)
-
-        to_extend.extend(int32_pack(len(bc.source_instructions)))
-        for inst in bc.source_instructions:
-            inst_name, inst_args = inst[0], inst[1:] if len(inst) > 1 else []
-            StringIO.dictify(inst_name, writer, to_extend, True, False)
-            to_extend.extend(int32_pack(len(inst_args)))
-            for arg in inst_args:
-                if isinstance(arg, TypeType):
-                    writer.toDict(GremlinType(arg().fqcn), to_extend)
-                else:
-                    writer.toDict(arg, to_extend)
-        return to_extend
-
-    @classmethod
-    def objectify(cls, buff, reader, nullable=True):
-        return cls.is_null(buff, reader, cls._read_bytecode, nullable)
-
-    @classmethod
-    def _read_bytecode(cls, b, r):
-        bytecode = Bytecode()
-
-        step_count = cls.read_int(b)
-        ix = 0
-        while ix < step_count:
-            inst = [r.toObject(b, DataType.string, False)]
-            inst_ct = cls.read_int(b)
-            iy = 0
-            while iy < inst_ct:
-                inst.append(r.readObject(b))
-                iy += 1
-            bytecode.step_instructions.append(inst)
-            ix += 1
-
-        source_count = cls.read_int(b)
-        ix = 0
-        while ix < source_count:
-            inst = [r.toObject(b, DataType.string, False)]
-            inst_ct = cls.read_int(b)
-            iy = 0
-            while iy < inst_ct:
-                inst.append(r.readObject(b))
-                iy += 1
-            bytecode.source_instructions.append(inst)
-            ix += 1
-
-        return bytecode
-
-
-class TraversalIO(BytecodeIO):
-    python_type = GraphTraversal
-
-
-class LambdaSerializer(_GraphBinaryTypeIO):
-
-    python_type = FunctionType
-    graphbinary_type = DataType.lambda_
-
-    @classmethod
-    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
-        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
-
-        lambda_result = obj()
-        script = lambda_result if isinstance(lambda_result, str) else lambda_result[0]
-        language = statics.default_lambda_language if isinstance(lambda_result, str) else lambda_result[1]
-
-        StringIO.dictify(language, writer, to_extend, True, False)
-
-        script_cleaned = script
-        script_args = -1
-
-        if language == "gremlin-jython" or language == "gremlin-python":
-            if not script.strip().startswith("lambda"):
-                script_cleaned = "lambda " + script
-            script_args = six.get_function_code(eval(script_cleaned)).co_argcount
-        elif language == "gremlin-groovy" and "->" in script:
-            # if the user has explicitly added parameters to the groovy closure then we can easily detect one or two
-            # arg lambdas - if we can't detect 1 or 2 then we just go with "unknown"
-            args = script[0:script.find("->")]
-            script_args = 2 if "," in args else 1
-
-        StringIO.dictify(script_cleaned, writer, to_extend, True, False)
-        to_extend.extend(int32_pack(script_args))
-
-        return to_extend
-
-
-class PSerializer(_GraphBinaryTypeIO):
-    graphbinary_type = DataType.p
-    python_type = P
-
-    @classmethod
-    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
-        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
-
-        StringIO.dictify(obj.operator, writer, to_extend, True, False)
-
-        args = []
-        if obj.other is None:
-            if isinstance(obj.value, ListType):
-                args = obj.value
-            else:
-                args.append(obj.value)
-        else:
-            args.append(obj.value)
-            args.append(obj.other)
-
-        to_extend.extend(int32_pack(len(args)))
-        for a in args:
-            writer.toDict(a, to_extend)
-
-        return to_extend
-
-
-class ScopeIO(_EnumIO):
-    graphbinary_type = DataType.scope
-    python_type = Scope
-
-
-class TIO(_EnumIO):
-    graphbinary_type = DataType.t
-    python_type = T
-
-
-class TraverserIO(_GraphBinaryTypeIO):
-    graphbinary_type = DataType.traverser
-    python_type = Traverser
-
-    @classmethod
-    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
-        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
-        to_extend.extend(int64_pack(obj.bulk))
-        writer.toDict(obj.object, to_extend)
-        return to_extend
-
-    @classmethod
-    def objectify(cls, buff, reader, nullable=True):
-        return cls.is_null(buff, reader, cls._read_traverser, nullable)
-
-    @classmethod
-    def _read_traverser(cls, b, r):
-        bulk = int64_unpack(b.read(8))
-        obj = r.readObject(b)
-        return Traverser(obj, bulk=bulk)
-
-
-class ByteIO(_GraphBinaryTypeIO):
-    python_type = SingleByte
-    graphbinary_type = DataType.byte
-
-    @classmethod
-    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
-        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
-        to_extend.extend(int8_pack(obj))
-        return to_extend
-
-    @classmethod
-    def objectify(cls, buff, reader, nullable=True):
-        return cls.is_null(buff, reader,
-                           lambda b, r: int.__new__(SingleByte, int8_unpack(b.read(1))),
-                           nullable)
-
-
-class ByteBufferIO(_GraphBinaryTypeIO):
-    python_type = ByteBufferType
-    graphbinary_type = DataType.bytebuffer
-
-    @classmethod
-    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
-        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
-        to_extend.extend(int32_pack(len(obj)))
-        to_extend.extend(obj)
-        return to_extend
-
-    @classmethod
-    def objectify(cls, buff, reader, nullable=True):
-        return cls.is_null(buff, reader, cls._read_bytebuffer, nullable)
-
-    @classmethod
-    def _read_bytebuffer(cls, b, r):
-        size = cls.read_int(b)
-        return ByteBufferType(b.read(size))
-
-
-class BooleanIO(_GraphBinaryTypeIO):
-    python_type = bool
-    graphbinary_type = DataType.boolean
-
-    @classmethod
-    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
-        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
-        to_extend.extend(int8_pack(0x01 if obj else 0x00))
-        return to_extend
-
-    @classmethod
-    def objectify(cls, buff, reader, nullable=True):
-        return cls.is_null(buff, reader,
-                           lambda b, r: True if int8_unpack(b.read(1)) == 0x01 else False,
-                           nullable)
-
-
-class TextPSerializer(_GraphBinaryTypeIO):
-    graphbinary_type = DataType.textp
-    python_type = TextP
-
-    @classmethod
-    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
-        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
-
-        StringIO.dictify(obj.operator, writer, to_extend, True, False)
-
-        args = []
-        if obj.other is None:
-            if isinstance(obj.value, ListType):
-                args = obj.value
-            else:
-                args.append(obj.value)
-        else:
-            args.append(obj.value)
-            args.append(obj.other)
-
-        to_extend.extend(int32_pack(len(args)))
-        for a in args:
-            writer.toDict(a, to_extend)
-
-        return to_extend
-
-
-class BulkSetDeserializer(_GraphBinaryTypeIO):
-
-    graphbinary_type = DataType.bulkset
-
-    @classmethod
-    def objectify(cls, buff, reader, nullable=True):
-        return cls.is_null(buff, reader, cls._read_bulkset, nullable)
-
-    @classmethod
-    def _read_bulkset(cls, b, r):
-        size = cls.read_int(b)
-        the_list = []
-        while size > 0:
-            itm = r.readObject(b)
-            bulk = int64_unpack(b.read(8))
-            for y in range(bulk):
-                the_list.append(itm)            
-            size = size - 1
-
-        return the_list
-
-
-class MetricsDeserializer(_GraphBinaryTypeIO):
-
-    graphbinary_type = DataType.metrics
-
-    @classmethod
-    def objectify(cls, buff, reader, nullable=True):
-        return cls.is_null(buff, reader, cls._read_metrics, nullable)
-
-    @classmethod
-    def _read_metrics(cls, b, r):
-        metricid = r.toObject(b, DataType.string, False)
-        name = r.toObject(b, DataType.string, False)
-        duration = r.toObject(b, DataType.long, nullable=False)
-        counts = r.toObject(b, DataType.map, nullable=False)
-        annotations = r.toObject(b, DataType.map, nullable=False)
-        metrics = r.toObject(b, DataType.list, nullable=False)
-
-        return {"id": metricid,
-                "name": name,
-                "dur": duration,
-                "counts": counts,
-                "annotations": annotations,
-                "metrics": metrics}
-
-
-class TraversalMetricsDeserializer(_GraphBinaryTypeIO):
-
-    graphbinary_type = DataType.traversalmetrics
-
-    @classmethod
-    def objectify(cls, buff, reader, nullable=True):
-        return cls.is_null(buff, reader, cls._read_traversalmetrics, nullable)
-
-    @classmethod
-    def _read_traversalmetrics(cls, b, r):
-        duration = r.toObject(b, DataType.long, nullable=False)
-        metrics = r.toObject(b, DataType.list, nullable=False)
-
-        return {"dur": duration,
-                "metrics": metrics}
-
-
-class ClassSerializer(_GraphBinaryTypeIO):
-    graphbinary_type = DataType.clazz
-    python_type = GremlinType
-
-    @classmethod
-    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
-        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
-        StringIO.dictify(obj.gremlin_type, writer, to_extend, True, False)
-        return to_extend
-
-
-class TraversalStrategySerializer(_GraphBinaryTypeIO):
-    graphbinary_type = DataType.traversalstrategy
-    python_type = TraversalStrategy
-
-    @classmethod
-    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
-        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
-
-        ClassSerializer.dictify(GremlinType(obj.fqcn), writer, to_extend, True, False)
-        conf = {k: cls._convert(v) for k, v in obj.configuration.items()}
-        MapIO.dictify(conf, writer, to_extend, True, False)
-
-        return to_extend
-
-    @classmethod
-    def _convert(cls, v):
-        return v.bytecode if isinstance(v, Traversal) else v
-
-
-class DurationIO(_GraphBinaryTypeIO):
-    python_type = timedelta
-    graphbinary_type = DataType.duration
-
-    @classmethod
-    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
-        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
-        LongIO.dictify(obj.seconds, writer, to_extend, True, False)
-        IntIO.dictify(obj.microseconds * 1000, writer, to_extend, True, False)
-        return to_extend
-
-    @classmethod
-    def objectify(cls, buff, reader, nullable=True):
-        return cls.is_null(buff, reader, cls._read_duration, nullable)
-    
-    @classmethod
-    def _read_duration(cls, b, r):
-        seconds = r.toObject(b, DataType.long, False)
-        nanos = r.toObject(b, DataType.int, False)
-        return timedelta(seconds=seconds, microseconds=nanos / 1000)
diff --git a/gremlin-python/src/main/jython/gremlin_python/structure/io/graphsonV2d0.py b/gremlin-python/src/main/jython/gremlin_python/structure/io/graphsonV2d0.py
deleted file mode 100644
index 2906dba..0000000
--- a/gremlin-python/src/main/jython/gremlin_python/structure/io/graphsonV2d0.py
+++ /dev/null
@@ -1,637 +0,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.
-#
-
-import calendar
-import datetime
-import json
-import uuid
-import math
-from collections import OrderedDict
-from decimal import *
-from datetime import timedelta
-
-import six
-from aenum import Enum
-from isodate import parse_duration, duration_isoformat
-
-from gremlin_python import statics
-from gremlin_python.statics import FloatType, FunctionType, IntType, LongType, TypeType, SingleByte, ByteBufferType, SingleChar
-from gremlin_python.process.traversal import Binding, Bytecode, P, TextP, Traversal, Traverser, TraversalStrategy
-from gremlin_python.structure.graph import Edge, Property, Vertex, VertexProperty, Path
-
-# When we fall back to a superclass's serializer, we iterate over this map.
-# We want that iteration order to be consistent, so we use an OrderedDict,
-# not a dict.
-_serializers = OrderedDict()
-_deserializers = {}
-
-
-class GraphSONTypeType(type):
-    def __new__(mcs, name, bases, dct):
-        cls = super(GraphSONTypeType, mcs).__new__(mcs, name, bases, dct)
-        if not name.startswith('_'):
-            if cls.python_type:
-                _serializers[cls.python_type] = cls
-            if cls.graphson_type:
-                _deserializers[cls.graphson_type] = cls
-        return cls
-
-
-class GraphSONUtil(object):
-    TYPE_KEY = "@type"
-    VALUE_KEY = "@value"
-
-    @classmethod
-    def typedValue(cls, type_name, value, prefix="g"):
-        out = {cls.TYPE_KEY: cls.formatType(prefix, type_name)}
-        if value is not None:
-            out[cls.VALUE_KEY] = value
-        return out
-
-    @classmethod
-    def formatType(cls, prefix, type_name):
-        return "%s:%s" % (prefix, type_name)
-
-
-# Read/Write classes split to follow precedence of the Java API
-class GraphSONWriter(object):
-    def __init__(self, serializer_map=None):
-        """
-        :param serializer_map: map from Python type to serializer instance implementing `dictify`
-        """
-        self.serializers = _serializers.copy()
-        if serializer_map:
-            self.serializers.update(serializer_map)
-
-    def writeObject(self, objectData):
-        # to JSON
-        return json.dumps(self.toDict(objectData), separators=(',', ':'))
-
-    def toDict(self, obj):
-        """
-        Encodes python objects in GraphSON type-tagged dict values
-        """
-        try:
-            return self.serializers[type(obj)].dictify(obj, self)
-        except KeyError:
-            for key, serializer in self.serializers.items():
-                if isinstance(obj, key):
-                    return serializer.dictify(obj, self)
-
-        # list and map are treated as normal json objs (could be isolated serializers)
-        if isinstance(obj, (list, set)):
-            return [self.toDict(o) for o in obj]
-        elif isinstance(obj, dict):
-            return dict((self.toDict(k), self.toDict(v)) for k, v in obj.items())
-        else:
-            return obj
-
-
-class GraphSONReader(object):
-    def __init__(self, deserializer_map=None):
-        """
-        :param deserializer_map: map from GraphSON type tag to deserializer instance implementing `objectify`
-        """
-        self.deserializers = _deserializers.copy()
-        if deserializer_map:
-            self.deserializers.update(deserializer_map)
-
-    def readObject(self, jsonData):
-        # from JSON
-        return self.toObject(json.loads(jsonData))
-
-    def toObject(self, obj):
-        """
-        Unpacks GraphSON type-tagged dict values into objects mapped in self.deserializers
-        """
-        if isinstance(obj, dict):
-            try:
-                return self.deserializers[obj[GraphSONUtil.TYPE_KEY]].objectify(obj[GraphSONUtil.VALUE_KEY], self)
-            except KeyError:
-                pass
-            # list and map are treated as normal json objs (could be isolated deserializers)
-            return dict((self.toObject(k), self.toObject(v)) for k, v in obj.items())
-        elif isinstance(obj, list):
-            return [self.toObject(o) for o in obj]
-        else:
-            return obj
-
-
-@six.add_metaclass(GraphSONTypeType)
-class _GraphSONTypeIO(object):
-    python_type = None
-    graphson_type = None
-
-    symbolMap = {"global_": "global", "as_": "as", "in_": "in", "and_": "and",
-                 "or_": "or", "is_": "is", "not_": "not", "from_": "from",
-                 "set_": "set", "list_": "list", "all_": "all", "with_": "with",
-                 "filter_": "filter", "id_": "id", "max_": "max", "min_": "min", "sum_": "sum"}
-
-    @classmethod
-    def unmangleKeyword(cls, symbol):
-        return cls.symbolMap.get(symbol, symbol)
-
-    def dictify(self, obj, writer):
-        raise NotImplementedError()
-
-    def objectify(self, d, reader):
-        raise NotImplementedError()
-
-
-class _BytecodeSerializer(_GraphSONTypeIO):
-    @classmethod
-    def _dictify_instructions(cls, instructions, writer):
-        out = []
-        for instruction in instructions:
-            inst = [instruction[0]]
-            inst.extend(writer.toDict(arg) for arg in instruction[1:])
-            out.append(inst)
-        return out
-
-    @classmethod
-    def dictify(cls, bytecode, writer):
-        if isinstance(bytecode, Traversal):
-            bytecode = bytecode.bytecode
-        out = {}
-        if bytecode.source_instructions:
-            out["source"] = cls._dictify_instructions(bytecode.source_instructions, writer)
-        if bytecode.step_instructions:
-            out["step"] = cls._dictify_instructions(bytecode.step_instructions, writer)
-        return GraphSONUtil.typedValue("Bytecode", out)
-
-class TraversalSerializer(_BytecodeSerializer):
-    python_type = Traversal
-
-
-class BytecodeSerializer(_BytecodeSerializer):
-    python_type = Bytecode
-
-
-class VertexSerializer(_GraphSONTypeIO):
-    python_type = Vertex
-    graphson_type = "g:Vertex"
-
-    @classmethod
-    def dictify(cls, vertex, writer):
-        return GraphSONUtil.typedValue("Vertex", {"id": writer.toDict(vertex.id),
-                                                  "label": writer.toDict(vertex.label)})
-
-
-class EdgeSerializer(_GraphSONTypeIO):
-    python_type = Edge
-    graphson_type = "g:Edge"
-
-    @classmethod
-    def dictify(cls, edge, writer):
-        return GraphSONUtil.typedValue("Edge", {"id": writer.toDict(edge.id),
-                                                "outV": writer.toDict(edge.outV.id),
-                                                "outVLabel": writer.toDict(edge.outV.label),
-                                                "label": writer.toDict(edge.label),
-                                                "inV": writer.toDict(edge.inV.id),
-                                                "inVLabel": writer.toDict(edge.inV.label)})
-
-
-class VertexPropertySerializer(_GraphSONTypeIO):
-    python_type = VertexProperty
-    graphson_type = "g:VertexProperty"
-
-    @classmethod
-    def dictify(cls, vertex_property, writer):
-        return GraphSONUtil.typedValue("VertexProperty", {"id": writer.toDict(vertex_property.id),
-                                                          "label": writer.toDict(vertex_property.label),
-                                                          "value": writer.toDict(vertex_property.value),
-                                                          "vertex": writer.toDict(vertex_property.vertex.id)})
-
-
-class PropertySerializer(_GraphSONTypeIO):
-    python_type = Property
-    graphson_type = "g:Property"
-
-    @classmethod
-    def dictify(cls, property, writer):
-        elementDict = writer.toDict(property.element)
-        if elementDict is not None:
-            valueDict = elementDict["@value"]
-            if "outVLabel" in valueDict:
-                del valueDict["outVLabel"]
-            if "inVLabel" in valueDict:
-                del valueDict["inVLabel"]
-            if "properties" in valueDict:
-                del valueDict["properties"]
-            if "value" in valueDict:
-                del valueDict["value"]
-        return GraphSONUtil.typedValue("Property", {"key": writer.toDict(property.key),
-                                                    "value": writer.toDict(property.value),
-                                                    "element": elementDict})
-
-
-class TraversalStrategySerializer(_GraphSONTypeIO):
-    python_type = TraversalStrategy
-
-    @classmethod
-    def dictify(cls, strategy, writer):
-        return GraphSONUtil.typedValue(strategy.strategy_name, writer.toDict(strategy.configuration))
-
-
-class TraverserIO(_GraphSONTypeIO):
-    python_type = Traverser
-    graphson_type = "g:Traverser"
-
-    @classmethod
-    def dictify(cls, traverser, writer):
-        return GraphSONUtil.typedValue("Traverser", {"value": writer.toDict(traverser.object),
-                                                     "bulk": writer.toDict(traverser.bulk)})
-
-    @classmethod
-    def objectify(cls, d, reader):
-        return Traverser(reader.toObject(d["value"]),
-                         reader.toObject(d["bulk"]))
-
-
-class EnumSerializer(_GraphSONTypeIO):
-    python_type = Enum
-
-    @classmethod
-    def dictify(cls, enum, _):
-        return GraphSONUtil.typedValue(cls.unmangleKeyword(type(enum).__name__),
-                                       cls.unmangleKeyword(str(enum.name)))
-
-
-class PSerializer(_GraphSONTypeIO):
-    python_type = P
-
-    @classmethod
-    def dictify(cls, p, writer):
-        out = {"predicate": p.operator,
-               "value": [writer.toDict(p.value), writer.toDict(p.other)] if p.other is not None else
-               writer.toDict(p.value)}
-        return GraphSONUtil.typedValue("P", out)
-
-
-class TextPSerializer(_GraphSONTypeIO):
-    python_type = TextP
-
-    @classmethod
-    def dictify(cls, p, writer):
-        out = {"predicate": p.operator,
-               "value": [writer.toDict(p.value), writer.toDict(p.other)] if p.other is not None else
-               writer.toDict(p.value)}
-        return GraphSONUtil.typedValue("TextP", out)
-
-
-class BindingSerializer(_GraphSONTypeIO):
-    python_type = Binding
-
-    @classmethod
-    def dictify(cls, binding, writer):
-        out = {"key": binding.key,
-               "value": writer.toDict(binding.value)}
-        return GraphSONUtil.typedValue("Binding", out)
-
-
-class LambdaSerializer(_GraphSONTypeIO):
-    python_type = FunctionType
-
-    @classmethod
-    def dictify(cls, lambda_object, writer):
-        lambda_result = lambda_object()
-        script = lambda_result if isinstance(lambda_result, str) else lambda_result[0]
-        language = statics.default_lambda_language if isinstance(lambda_result, str) else lambda_result[1]
-        out = {"script": script,
-               "language": language}
-        if language == "gremlin-jython" or language == "gremlin-python":
-            if not script.strip().startswith("lambda"):
-                script = "lambda " + script
-                out["script"] = script
-            out["arguments"] = six.get_function_code(eval(out["script"])).co_argcount
-        elif language == "gremlin-groovy" and "->" in script:
-            # if the user has explicitly added parameters to the groovy closure then we can easily detect one or two
-            # arg lambdas - if we can't detect 1 or 2 then we just go with "unknown"
-            args = script[0:script.find("->")]
-            out["arguments"] = 2 if "," in args else 1
-        else:
-            out["arguments"] = -1
-
-        return GraphSONUtil.typedValue("Lambda", out)
-
-
-class TypeSerializer(_GraphSONTypeIO):
-    python_type = TypeType
-
-    @classmethod
-    def dictify(cls, typ, writer):
-        return writer.toDict(typ())
-
-
-class UUIDIO(_GraphSONTypeIO):
-    python_type = uuid.UUID
-    graphson_type = "g:UUID"
-    graphson_base_type = "UUID"
-
-    @classmethod
-    def dictify(cls, obj, writer):
-        return GraphSONUtil.typedValue(cls.graphson_base_type, str(obj))
-
-    @classmethod
-    def objectify(cls, d, reader):
-        return cls.python_type(d)
-
-
-class DateIO(_GraphSONTypeIO):
-    python_type = datetime.datetime
-    graphson_type = "g:Date"
-    graphson_base_type = "Date"
-
-    @classmethod
-    def dictify(cls, obj, writer):
-        try:
-            timestamp_seconds = calendar.timegm(obj.utctimetuple())
-            pts = timestamp_seconds * 1e3 + getattr(obj, 'microsecond', 0) / 1e3
-        except AttributeError:
-            pts = calendar.timegm(obj.timetuple()) * 1e3
-
-        ts = int(round(pts))
-        return GraphSONUtil.typedValue(cls.graphson_base_type, ts)
-
-    @classmethod
-    def objectify(cls, ts, reader):
-        # Python timestamp expects seconds
-        return datetime.datetime.utcfromtimestamp(ts / 1000.0)
-
-
-# Based on current implementation, this class must always be declared before FloatIO.
-# Seems pretty fragile for future maintainers. Maybe look into this.
-class TimestampIO(_GraphSONTypeIO):
-    """A timestamp in Python is type float"""
-    python_type = statics.timestamp
-    graphson_type = "g:Timestamp"
-    graphson_base_type = "Timestamp"
-
-    @classmethod
-    def dictify(cls, obj, writer):
-        # Java timestamp expects milliseconds integer
-        # Have to use int because of legacy Python
-        ts = int(round(obj * 1000))
-        return GraphSONUtil.typedValue(cls.graphson_base_type, ts)
-
-    @classmethod
-    def objectify(cls, ts, reader):
-        # Python timestamp expects seconds
-        return cls.python_type(ts / 1000.0)
-
-
-class _NumberIO(_GraphSONTypeIO):
-    @classmethod
-    def dictify(cls, n, writer):
-        if isinstance(n, bool):  # because isinstance(False, int) and isinstance(True, int)
-            return n
-        return GraphSONUtil.typedValue(cls.graphson_base_type, n)
-
-    @classmethod
-    def objectify(cls, v, _):
-        return cls.python_type(v)
-
-
-class FloatIO(_NumberIO):
-    python_type = FloatType
-    graphson_type = "g:Float"
-    graphson_base_type = "Float"
-
-    @classmethod
-    def dictify(cls, n, writer):
-        if isinstance(n, bool):  # because isinstance(False, int) and isinstance(True, int)
-            return n
-        elif math.isnan(n):
-            return GraphSONUtil.typedValue(cls.graphson_base_type, "NaN")
-        elif math.isinf(n) and n > 0:
-            return GraphSONUtil.typedValue(cls.graphson_base_type, "Infinity")
-        elif math.isinf(n) and n < 0:
-            return GraphSONUtil.typedValue(cls.graphson_base_type, "-Infinity")
-        else:
-            return GraphSONUtil.typedValue(cls.graphson_base_type, n)
-
-    @classmethod
-    def objectify(cls, v, _):
-        if isinstance(v, str):
-            if v == 'NaN':
-                return float('nan')
-            elif v == "Infinity":
-                return float('inf')
-            elif v == "-Infinity":
-                return float('-inf')
-
-        return cls.python_type(v)
-
-
-class BigDecimalIO(_NumberIO):
-    python_type = Decimal
-    graphson_type = "gx:BigDecimal"
-    graphson_base_type = "BigDecimal"
-
-    @classmethod
-    def dictify(cls, n, writer):
-        if isinstance(n, bool):  # because isinstance(False, int) and isinstance(True, int)
-            return n
-        elif math.isnan(n):
-            return GraphSONUtil.typedValue(cls.graphson_base_type, "NaN", "gx")
-        elif math.isinf(n) and n > 0:
-            return GraphSONUtil.typedValue(cls.graphson_base_type, "Infinity", "gx")
-        elif math.isinf(n) and n < 0:
-            return GraphSONUtil.typedValue(cls.graphson_base_type, "-Infinity", "gx")
-        else:
-            return GraphSONUtil.typedValue(cls.graphson_base_type, str(n), "gx")
-
-    @classmethod
-    def objectify(cls, v, _):
-        if isinstance(v, str):
-            if v == 'NaN':
-                return Decimal('nan')
-            elif v == "Infinity":
-                return Decimal('inf')
-            elif v == "-Infinity":
-                return Decimal('-inf')
-
-        return Decimal(v)
-
-
-class DoubleIO(FloatIO):
-    graphson_type = "g:Double"
-    graphson_base_type = "Double"
-
-
-class Int64IO(_NumberIO):
-    python_type = LongType
-    graphson_type = "g:Int64"
-    graphson_base_type = "Int64"
-
-    @classmethod
-    def dictify(cls, n, writer):
-        # if we exceed Java long range then we need a BigInteger
-        if isinstance(n, bool):
-            return n
-        elif n < -9223372036854775808 or n > 9223372036854775807:
-            return GraphSONUtil.typedValue("BigInteger", str(n), "gx")
-        else:
-            return GraphSONUtil.typedValue(cls.graphson_base_type, n)
-
-
-class BigIntegerIO(Int64IO):
-    graphson_type = "gx:BigInteger"
-
-
-class Int32IO(Int64IO):
-    python_type = IntType
-    graphson_type = "g:Int32"
-    graphson_base_type = "Int32"
-
-    @classmethod
-    def dictify(cls, n, writer):
-        # if we exceed Java int range then we need a long
-        if isinstance(n, bool):
-            return n
-        elif n < -9223372036854775808 or n > 9223372036854775807:
-            return GraphSONUtil.typedValue("BigInteger", str(n), "gx")
-        elif n < -2147483648 or n > 2147483647:
-            return GraphSONUtil.typedValue("Int64", n)
-        else:
-            return GraphSONUtil.typedValue(cls.graphson_base_type, n)
-
-
-class ByteIO(_NumberIO):
-    python_type = SingleByte
-    graphson_type = "gx:Byte"
-    graphson_base_type = "Byte"
-
-    @classmethod
-    def dictify(cls, n, writer):
-        if isinstance(n, bool):  # because isinstance(False, int) and isinstance(True, int)
-            return n
-        return GraphSONUtil.typedValue(cls.graphson_base_type, n, "gx")
-
-    @classmethod
-    def objectify(cls, v, _):
-        return int.__new__(SingleByte, v)
-
-
-class ByteBufferIO(_GraphSONTypeIO):
-    python_type = ByteBufferType
-    graphson_type = "gx:ByteBuffer"
-    graphson_base_type = "ByteBuffer"
-
-    @classmethod
-    def dictify(cls, n, writer):
-        return GraphSONUtil.typedValue(cls.graphson_base_type, "".join(chr(x) for x in n), "gx")
-
-    @classmethod
-    def objectify(cls, v, _):
-        return cls.python_type(v, "utf8")
-
-
-class CharIO(_GraphSONTypeIO):
-    python_type = SingleChar
-    graphson_type = "gx:Char"
-    graphson_base_type = "Char"
-
-    @classmethod
-    def dictify(cls, n, writer):
-        return GraphSONUtil.typedValue(cls.graphson_base_type, n, "gx")
-
-    @classmethod
-    def objectify(cls, v, _):
-        return str.__new__(SingleChar, v)
-
-
-class DurationIO(_GraphSONTypeIO):
-    python_type = timedelta
-    graphson_type = "gx:Duration"
-    graphson_base_type = "Duration"
-
-    @classmethod
-    def dictify(cls, n, writer):
-        return GraphSONUtil.typedValue(cls.graphson_base_type, duration_isoformat(n), "gx")
-
-    @classmethod
-    def objectify(cls, v, _):
-        return parse_duration(v)
-
-
-class VertexDeserializer(_GraphSONTypeIO):
-    graphson_type = "g:Vertex"
-
-    @classmethod
-    def objectify(cls, d, reader):
-        return Vertex(reader.toObject(d["id"]), d.get("label", "vertex"))
-
-
-class EdgeDeserializer(_GraphSONTypeIO):
-    graphson_type = "g:Edge"
-
-    @classmethod
-    def objectify(cls, d, reader):
-        return Edge(reader.toObject(d["id"]),
-                    Vertex(reader.toObject(d["outV"]), d.get("outVLabel", "vertex")),
-                    d.get("label", "edge"),
-                    Vertex(reader.toObject(d["inV"]), d.get("inVLabel", "vertex")))
-
-
-class VertexPropertyDeserializer(_GraphSONTypeIO):
-    graphson_type = "g:VertexProperty"
-
-    @classmethod
-    def objectify(cls, d, reader):
-        vertex = Vertex(reader.toObject(d.get("vertex"))) if "vertex" in d else None
-        return VertexProperty(reader.toObject(d["id"]),
-                              d["label"],
-                              reader.toObject(d["value"]),
-                              vertex)
-
-
-class PropertyDeserializer(_GraphSONTypeIO):
-    graphson_type = "g:Property"
-
-    @classmethod
-    def objectify(cls, d, reader):
-        element = reader.toObject(d["element"]) if "element" in d else None
-        return Property(d["key"], reader.toObject(d["value"]), element)
-
-
-class PathDeserializer(_GraphSONTypeIO):
-    graphson_type = "g:Path"
-
-    @classmethod
-    def objectify(cls, d, reader):
-        labels = [set(label) for label in d["labels"]]
-        objects = [reader.toObject(o) for o in d["objects"]]
-        return Path(labels, objects)
-
-
-class TraversalMetricsDeserializer(_GraphSONTypeIO):
-    graphson_type = "g:TraversalMetrics"
-
-    @classmethod
-    def objectify(cls, d, reader):
-        return reader.toObject(d)
-
-
-class MetricsDeserializer(_GraphSONTypeIO):
-    graphson_type = "g:Metrics"
-
-    @classmethod
-    def objectify(cls, d, reader):
-        return reader.toObject(d)
diff --git a/gremlin-python/src/main/jython/gremlin_python/structure/io/graphsonV3d0.py b/gremlin-python/src/main/jython/gremlin_python/structure/io/graphsonV3d0.py
deleted file mode 100644
index b15aca6..0000000
--- a/gremlin-python/src/main/jython/gremlin_python/structure/io/graphsonV3d0.py
+++ /dev/null
@@ -1,755 +0,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.
-import calendar
-import datetime
-import json
-import uuid
-import math
-from collections import OrderedDict
-from decimal import *
-import logging
-from datetime import timedelta
-
-import six
-from aenum import Enum
-from isodate import parse_duration, duration_isoformat
-
-from gremlin_python import statics
-from gremlin_python.statics import FloatType, FunctionType, IntType, LongType, TypeType, DictType, ListType, SetType, SingleByte, ByteBufferType, SingleChar
-from gremlin_python.process.traversal import Binding, Bytecode, Direction, P, TextP, Traversal, Traverser, TraversalStrategy, T
-from gremlin_python.structure.graph import Edge, Property, Vertex, VertexProperty, Path
-
-log = logging.getLogger(__name__)
-
-# When we fall back to a superclass's serializer, we iterate over this map.
-# We want that iteration order to be consistent, so we use an OrderedDict,
-# not a dict.
-_serializers = OrderedDict()
-_deserializers = {}
-
-
-class GraphSONTypeType(type):
-    def __new__(mcs, name, bases, dct):
-        cls = super(GraphSONTypeType, mcs).__new__(mcs, name, bases, dct)
-        if not name.startswith('_'):
-            if cls.python_type:
-                _serializers[cls.python_type] = cls
-            if cls.graphson_type:
-                _deserializers[cls.graphson_type] = cls
-        return cls
-
-
-class GraphSONUtil(object):
-    TYPE_KEY = "@type"
-    VALUE_KEY = "@value"
-
-    @classmethod
-    def typedValue(cls, type_name, value, prefix="g"):
-        out = {cls.TYPE_KEY: cls.formatType(prefix, type_name)}
-        if value is not None:
-            out[cls.VALUE_KEY] = value
-        return out
-
-    @classmethod
-    def formatType(cls, prefix, type_name):
-        return "%s:%s" % (prefix, type_name)
-
-
-# Read/Write classes split to follow precedence of the Java API
-class GraphSONWriter(object):
-    def __init__(self, serializer_map=None):
-        """
-        :param serializer_map: map from Python type to serializer instance implementing `dictify`
-        """
-        self.serializers = _serializers.copy()
-        if serializer_map:
-            self.serializers.update(serializer_map)
-
-    def writeObject(self, objectData):
-        # to JSON
-        return json.dumps(self.toDict(objectData), separators=(',', ':'))
-
-    def toDict(self, obj):
-        """
-        Encodes python objects in GraphSON type-tagged dict values
-        """
-        try:
-            return self.serializers[type(obj)].dictify(obj, self)
-        except KeyError:
-            for key, serializer in self.serializers.items():
-                if isinstance(obj, key):
-                    return serializer.dictify(obj, self)
-
-        if isinstance(obj, dict):
-            return dict((self.toDict(k), self.toDict(v)) for k, v in obj.items())
-        elif isinstance(obj, set):
-            return set([self.toDict(o) for o in obj])
-        elif isinstance(obj, list):
-            return [self.toDict(o) for o in obj]
-        else:
-            return obj
-
-
-class GraphSONReader(object):
-    def __init__(self, deserializer_map=None):
-        """
-        :param deserializer_map: map from GraphSON type tag to deserializer instance implementing `objectify`
-        """
-        self.deserializers = _deserializers.copy()
-        if deserializer_map:
-            self.deserializers.update(deserializer_map)
-
-    def readObject(self, jsonData):
-        # from JSON
-        return self.toObject(json.loads(jsonData))
-
-    def toObject(self, obj):
-        """
-        Unpacks GraphSON type-tagged dict values into objects mapped in self.deserializers
-        """
-        if isinstance(obj, dict):
-            try:
-                return self.deserializers[obj[GraphSONUtil.TYPE_KEY]].objectify(obj[GraphSONUtil.VALUE_KEY], self)
-            except KeyError:
-                pass
-            return dict((self.toObject(k), self.toObject(v)) for k, v in obj.items())
-        elif isinstance(obj, set):
-            return set([self.toObject(o) for o in obj])
-        elif isinstance(obj, list):
-            return [self.toObject(o) for o in obj]
-        else:
-            return obj
-
-
-@six.add_metaclass(GraphSONTypeType)
-class _GraphSONTypeIO(object):
-    python_type = None
-    graphson_type = None
-
-    symbolMap = {"global_": "global", "as_": "as", "in_": "in", "and_": "and",
-                 "or_": "or", "is_": "is", "not_": "not", "from_": "from",
-                 "set_": "set", "list_": "list", "all_": "all", "with_": "with",
-                 "filter_": "filter", "id_": "id", "max_": "max", "min_": "min", "sum_": "sum"}
-
-    @classmethod
-    def unmangleKeyword(cls, symbol):
-        return cls.symbolMap.get(symbol, symbol)
-
-    def dictify(self, obj, writer):
-        raise NotImplementedError()
-
-    def objectify(self, d, reader):
-        raise NotImplementedError()
-
-
-class _BytecodeSerializer(_GraphSONTypeIO):
-    @classmethod
-    def _dictify_instructions(cls, instructions, writer):
-        out = []
-        for instruction in instructions:
-            inst = [instruction[0]]
-            inst.extend(writer.toDict(arg) for arg in instruction[1:])
-            out.append(inst)
-        return out
-
-    @classmethod
-    def dictify(cls, bytecode, writer):
-        if isinstance(bytecode, Traversal):
-            bytecode = bytecode.bytecode
-        out = {}
-        if bytecode.source_instructions:
-            out["source"] = cls._dictify_instructions(bytecode.source_instructions, writer)
-        if bytecode.step_instructions:
-            out["step"] = cls._dictify_instructions(bytecode.step_instructions, writer)
-        return GraphSONUtil.typedValue("Bytecode", out)
-
-
-class TraversalSerializer(_BytecodeSerializer):
-    python_type = Traversal
-
-
-class BytecodeSerializer(_BytecodeSerializer):
-    python_type = Bytecode
-
-
-class VertexSerializer(_GraphSONTypeIO):
-    python_type = Vertex
-    graphson_type = "g:Vertex"
-
-    @classmethod
-    def dictify(cls, vertex, writer):
-        return GraphSONUtil.typedValue("Vertex", {"id": writer.toDict(vertex.id),
-                                                  "label": writer.toDict(vertex.label)})
-
-
-class EdgeSerializer(_GraphSONTypeIO):
-    python_type = Edge
-    graphson_type = "g:Edge"
-
-    @classmethod
-    def dictify(cls, edge, writer):
-        return GraphSONUtil.typedValue("Edge", {"id": writer.toDict(edge.id),
-                                                "outV": writer.toDict(edge.outV.id),
-                                                "outVLabel": writer.toDict(edge.outV.label),
-                                                "label": writer.toDict(edge.label),
-                                                "inV": writer.toDict(edge.inV.id),
-                                                "inVLabel": writer.toDict(edge.inV.label)})
-
-
-class VertexPropertySerializer(_GraphSONTypeIO):
-    python_type = VertexProperty
-    graphson_type = "g:VertexProperty"
-
-    @classmethod
-    def dictify(cls, vertex_property, writer):
-        return GraphSONUtil.typedValue("VertexProperty", {"id": writer.toDict(vertex_property.id),
-                                                          "label": writer.toDict(vertex_property.label),
-                                                          "value": writer.toDict(vertex_property.value),
-                                                          "vertex": writer.toDict(vertex_property.vertex.id)})
-
-
-class PropertySerializer(_GraphSONTypeIO):
-    python_type = Property
-    graphson_type = "g:Property"
-
-    @classmethod
-    def dictify(cls, property, writer):
-        elementDict = writer.toDict(property.element)
-        if elementDict is not None:
-            valueDict = elementDict["@value"]
-            if "outVLabel" in valueDict:
-                del valueDict["outVLabel"]
-            if "inVLabel" in valueDict:
-                del valueDict["inVLabel"]
-            if "properties" in valueDict:
-                del valueDict["properties"]
-            if "value" in valueDict:
-                del valueDict["value"]
-        return GraphSONUtil.typedValue("Property", {"key": writer.toDict(property.key),
-                                                    "value": writer.toDict(property.value),
-                                                    "element": elementDict})
-
-
-class TraversalStrategySerializer(_GraphSONTypeIO):
-    python_type = TraversalStrategy
-
-    @classmethod
-    def dictify(cls, strategy, writer):
-        configuration = {}
-        for key in strategy.configuration:
-            configuration[key] = writer.toDict(strategy.configuration[key])
-        return GraphSONUtil.typedValue(strategy.strategy_name, configuration)
-
-
-class TraverserIO(_GraphSONTypeIO):
-    python_type = Traverser
-    graphson_type = "g:Traverser"
-
-    @classmethod
-    def dictify(cls, traverser, writer):
-        return GraphSONUtil.typedValue("Traverser", {"value": writer.toDict(traverser.object),
-                                                     "bulk": writer.toDict(traverser.bulk)})
-
-    @classmethod
-    def objectify(cls, d, reader):
-        return Traverser(reader.toObject(d["value"]),
-                         reader.toObject(d["bulk"]))
-
-
-class EnumSerializer(_GraphSONTypeIO):
-    python_type = Enum
-
-    @classmethod
-    def dictify(cls, enum, _):
-        return GraphSONUtil.typedValue(cls.unmangleKeyword(type(enum).__name__),
-                                       cls.unmangleKeyword(str(enum.name)))
-
-
-class PSerializer(_GraphSONTypeIO):
-    python_type = P
-
-    @classmethod
-    def dictify(cls, p, writer):
-        out = {"predicate": p.operator,
-               "value": [writer.toDict(p.value), writer.toDict(p.other)] if p.other is not None else
-               writer.toDict(p.value)}
-        return GraphSONUtil.typedValue("P", out)
-
-
-class TextPSerializer(_GraphSONTypeIO):
-    python_type = TextP
-
-    @classmethod
-    def dictify(cls, p, writer):
-        out = {"predicate": p.operator,
-               "value": [writer.toDict(p.value), writer.toDict(p.other)] if p.other is not None else
-               writer.toDict(p.value)}
-        return GraphSONUtil.typedValue("TextP", out)
-
-
-class BindingSerializer(_GraphSONTypeIO):
-    python_type = Binding
-
-    @classmethod
-    def dictify(cls, binding, writer):
-        out = {"key": binding.key,
-               "value": writer.toDict(binding.value)}
-        return GraphSONUtil.typedValue("Binding", out)
-
-
-class LambdaSerializer(_GraphSONTypeIO):
-    python_type = FunctionType
-
-    @classmethod
-    def dictify(cls, lambda_object, writer):
-        lambda_result = lambda_object()
-        script = lambda_result if isinstance(lambda_result, str) else lambda_result[0]
-        language = statics.default_lambda_language if isinstance(lambda_result, str) else lambda_result[1]
-        out = {"script": script,
-               "language": language}
-        if language == "gremlin-jython" or language == "gremlin-python":
-            if not script.strip().startswith("lambda"):
-                script = "lambda " + script
-                out["script"] = script
-            out["arguments"] = six.get_function_code(eval(out["script"])).co_argcount
-        elif language == "gremlin-groovy" and "->" in script:
-            # if the user has explicitly added parameters to the groovy closure then we can easily detect one or two
-            # arg lambdas - if we can't detect 1 or 2 then we just go with "unknown"
-            args = script[0:script.find("->")]
-            out["arguments"] = 2 if "," in args else 1
-        else:
-            out["arguments"] = -1
-
-        return GraphSONUtil.typedValue("Lambda", out)
-
-
-class TypeSerializer(_GraphSONTypeIO):
-    python_type = TypeType
-
-    @classmethod
-    def dictify(cls, typ, writer):
-        return writer.toDict(typ())
-
-
-class UUIDIO(_GraphSONTypeIO):
-    python_type = uuid.UUID
-    graphson_type = "g:UUID"
-    graphson_base_type = "UUID"
-
-    @classmethod
-    def dictify(cls, obj, writer):
-        return GraphSONUtil.typedValue(cls.graphson_base_type, str(obj))
-
-    @classmethod
-    def objectify(cls, d, reader):
-        return cls.python_type(d)
-
-
-class DateIO(_GraphSONTypeIO):
-    python_type = datetime.datetime
-    graphson_type = "g:Date"
-    graphson_base_type = "Date"
-
-    @classmethod
-    def dictify(cls, obj, writer):
-        try:
-            timestamp_seconds = calendar.timegm(obj.utctimetuple())
-            pts = timestamp_seconds * 1e3 + getattr(obj, 'microsecond', 0) / 1e3
-        except AttributeError:
-            pts = calendar.timegm(obj.timetuple()) * 1e3
-
-        ts = int(round(pts))
-        return GraphSONUtil.typedValue(cls.graphson_base_type, ts)
-
-    @classmethod
-    def objectify(cls, ts, reader):
-        # Python timestamp expects seconds
-        return datetime.datetime.utcfromtimestamp(ts / 1000.0)
-
-
-# Based on current implementation, this class must always be declared before FloatIO.
-# Seems pretty fragile for future maintainers. Maybe look into this.
-class TimestampIO(_GraphSONTypeIO):
-    """A timestamp in Python is type float"""
-    python_type = statics.timestamp
-    graphson_type = "g:Timestamp"
-    graphson_base_type = "Timestamp"
-
-    @classmethod
-    def dictify(cls, obj, writer):
-        # Java timestamp expects milliseconds integer
-        # Have to use int because of legacy Python
-        ts = int(round(obj * 1000))
-        return GraphSONUtil.typedValue(cls.graphson_base_type, ts)
-
-    @classmethod
-    def objectify(cls, ts, reader):
-        # Python timestamp expects seconds
-        return cls.python_type(ts / 1000.0)
-
-
-class _NumberIO(_GraphSONTypeIO):
-    @classmethod
-    def dictify(cls, n, writer):
-        if isinstance(n, bool):  # because isinstance(False, int) and isinstance(True, int)
-            return n
-        return GraphSONUtil.typedValue(cls.graphson_base_type, n)
-
-    @classmethod
-    def objectify(cls, v, _):
-        return cls.python_type(v)
-
-
-class ListIO(_GraphSONTypeIO):
-    python_type = ListType
-    graphson_type = "g:List"
-
-    @classmethod
-    def dictify(cls, l, writer):
-        new_list = []
-        for obj in l:
-            new_list.append(writer.toDict(obj))
-        return GraphSONUtil.typedValue("List", new_list)
-
-    @classmethod
-    def objectify(cls, l, reader):
-        new_list = []
-        for obj in l:
-            new_list.append(reader.toObject(obj))
-        return new_list
-
-
-class SetIO(_GraphSONTypeIO):
-    python_type = SetType
-    graphson_type = "g:Set"
-
-    @classmethod
-    def dictify(cls, s, writer):
-        new_list = []
-        for obj in s:
-            new_list.append(writer.toDict(obj))
-        return GraphSONUtil.typedValue("Set", new_list)
-
-    @classmethod
-    def objectify(cls, s, reader):
-        """
-        By default, returns a python set
-
-        In case Java returns numeric values of different types which
-        python don't recognize, coerce and return a list.
-        See comments of TINKERPOP-1844 for more details
-        """
-        new_list = [reader.toObject(obj) for obj in s]
-        new_set = set(new_list)
-        if len(new_list) != len(new_set):
-            log.warning("Coercing g:Set to list due to java numeric values. "
-                        "See TINKERPOP-1844 for more details.")
-            return new_list
-
-        return new_set
-
-
-class MapType(_GraphSONTypeIO):
-    python_type = DictType
-    graphson_type = "g:Map"
-
-    @classmethod
-    def dictify(cls, d, writer):
-        l = []
-        for key in d:
-            l.append(writer.toDict(key))
-            l.append(writer.toDict(d[key]))
-        return GraphSONUtil.typedValue("Map", l)
-
-    @classmethod
-    def objectify(cls, l, reader):
-        new_dict = {}
-        if len(l) > 0:
-            x = 0
-            while x < len(l):
-                new_dict[reader.toObject(l[x])] = reader.toObject(l[x + 1])
-                x = x + 2
-        return new_dict
-
-
-class BulkSetIO(_GraphSONTypeIO):
-    graphson_type = "g:BulkSet"
-
-    @classmethod
-    def objectify(cls, l, reader):
-        new_list = []
-
-        # this approach basically mimics what currently existed in 3.3.4 and prior versions where BulkSet is
-        # basically just coerced to list. the limitation here is that if the value of a bulk exceeds the size of
-        # a list (into the long space) then stuff won't work nice.
-        if len(l) > 0:
-            x = 0
-            while x < len(l):
-                obj = reader.toObject(l[x])
-                bulk = reader.toObject(l[x + 1])
-                for y in range(bulk):
-                    new_list.append(obj)
-                x = x + 2
-        return new_list
-
-
-class FloatIO(_NumberIO):
-    python_type = FloatType
-    graphson_type = "g:Float"
-    graphson_base_type = "Float"
-
-    @classmethod
-    def dictify(cls, n, writer):
-        if isinstance(n, bool):  # because isinstance(False, int) and isinstance(True, int)
-            return n
-        elif math.isnan(n):
-            return GraphSONUtil.typedValue(cls.graphson_base_type, "NaN")
-        elif math.isinf(n) and n > 0:
-            return GraphSONUtil.typedValue(cls.graphson_base_type, "Infinity")
-        elif math.isinf(n) and n < 0:
-            return GraphSONUtil.typedValue(cls.graphson_base_type, "-Infinity")
-        else:
-            return GraphSONUtil.typedValue(cls.graphson_base_type, n)
-
-    @classmethod
-    def objectify(cls, v, _):
-        if isinstance(v, str):
-            if v == 'NaN':
-                return float('nan')
-            elif v == "Infinity":
-                return float('inf')
-            elif v == "-Infinity":
-                return float('-inf')
-
-        return cls.python_type(v)
-
-
-class BigDecimalIO(_NumberIO):
-    python_type = Decimal
-    graphson_type = "gx:BigDecimal"
-    graphson_base_type = "BigDecimal"
-
-    @classmethod
-    def dictify(cls, n, writer):
-        if isinstance(n, bool):  # because isinstance(False, int) and isinstance(True, int)
-            return n
-        elif math.isnan(n):
-            return GraphSONUtil.typedValue(cls.graphson_base_type, "NaN", "gx")
-        elif math.isinf(n) and n > 0:
-            return GraphSONUtil.typedValue(cls.graphson_base_type, "Infinity", "gx")
-        elif math.isinf(n) and n < 0:
-            return GraphSONUtil.typedValue(cls.graphson_base_type, "-Infinity", "gx")
-        else:
-            return GraphSONUtil.typedValue(cls.graphson_base_type, str(n), "gx")
-
-    @classmethod
-    def objectify(cls, v, _):
-        if isinstance(v, str):
-            if v == 'NaN':
-                return Decimal('nan')
-            elif v == "Infinity":
-                return Decimal('inf')
-            elif v == "-Infinity":
-                return Decimal('-inf')
-
-        return Decimal(v)
-
-
-class DoubleIO(FloatIO):
-    graphson_type = "g:Double"
-    graphson_base_type = "Double"
-
-
-class Int64IO(_NumberIO):
-    python_type = LongType
-    graphson_type = "g:Int64"
-    graphson_base_type = "Int64"
-
-    @classmethod
-    def dictify(cls, n, writer):
-        # if we exceed Java long range then we need a BigInteger
-        if isinstance(n, bool):
-            return n
-        elif n < -9223372036854775808 or n > 9223372036854775807:
-            return GraphSONUtil.typedValue("BigInteger", str(n), "gx")
-        else:
-            return GraphSONUtil.typedValue(cls.graphson_base_type, n)
-
-
-class BigIntegerIO(Int64IO):
-    graphson_type = "gx:BigInteger"
-
-
-class Int32IO(Int64IO):
-    python_type = IntType
-    graphson_type = "g:Int32"
-    graphson_base_type = "Int32"
-
-    @classmethod
-    def dictify(cls, n, writer):
-        # if we exceed Java int range then we need a long
-        if isinstance(n, bool):
-            return n
-        elif n < -9223372036854775808 or n > 9223372036854775807:
-            return GraphSONUtil.typedValue("BigInteger", str(n), "gx")
-        elif n < -2147483648 or n > 2147483647:
-            return GraphSONUtil.typedValue("Int64", n)
-        else:
-            return GraphSONUtil.typedValue(cls.graphson_base_type, n)
-
-class ByteIO(_NumberIO):
-    python_type = SingleByte
-    graphson_type = "gx:Byte"
-    graphson_base_type = "Byte"
-
-    @classmethod
-    def dictify(cls, n, writer):
-        if isinstance(n, bool):  # because isinstance(False, int) and isinstance(True, int)
-            return n
-        return GraphSONUtil.typedValue(cls.graphson_base_type, n, "gx")
-
-    @classmethod
-    def objectify(cls, v, _):
-        return int.__new__(SingleByte, v)
-
-
-class ByteBufferIO(_GraphSONTypeIO):
-    python_type = ByteBufferType
-    graphson_type = "gx:ByteBuffer"
-    graphson_base_type = "ByteBuffer"
-
-    @classmethod
-    def dictify(cls, n, writer):
-        return GraphSONUtil.typedValue(cls.graphson_base_type, "".join(chr(x) for x in n), "gx")
-
-    @classmethod
-    def objectify(cls, v, _):
-        return cls.python_type(v, "utf8")
-
-
-class CharIO(_GraphSONTypeIO):
-    python_type = SingleChar
-    graphson_type = "gx:Char"
-    graphson_base_type = "Char"
-
-    @classmethod
-    def dictify(cls, n, writer):
-        return GraphSONUtil.typedValue(cls.graphson_base_type, n, "gx")
-
-    @classmethod
-    def objectify(cls, v, _):
-        return str.__new__(SingleChar, v)
-
-
-class DurationIO(_GraphSONTypeIO):
-    python_type = timedelta
-    graphson_type = "gx:Duration"
-    graphson_base_type = "Duration"
-
-    @classmethod
-    def dictify(cls, n, writer):
-        return GraphSONUtil.typedValue(cls.graphson_base_type, duration_isoformat(n), "gx")
-
-    @classmethod
-    def objectify(cls, v, _):
-        return parse_duration(v)
-
-
-class VertexDeserializer(_GraphSONTypeIO):
-    graphson_type = "g:Vertex"
-
-    @classmethod
-    def objectify(cls, d, reader):
-        return Vertex(reader.toObject(d["id"]), d.get("label", "vertex"))
-
-
-class EdgeDeserializer(_GraphSONTypeIO):
-    graphson_type = "g:Edge"
-
-    @classmethod
-    def objectify(cls, d, reader):
-        return Edge(reader.toObject(d["id"]),
-                    Vertex(reader.toObject(d["outV"]), d.get("outVLabel", "vertex")),
-                    d.get("label", "edge"),
-                    Vertex(reader.toObject(d["inV"]), d.get("inVLabel", "vertex")))
-
-
-class VertexPropertyDeserializer(_GraphSONTypeIO):
-    graphson_type = "g:VertexProperty"
-
-    @classmethod
-    def objectify(cls, d, reader):
-        vertex = Vertex(reader.toObject(d.get("vertex"))) if "vertex" in d else None
-        return VertexProperty(reader.toObject(d["id"]),
-                              d["label"],
-                              reader.toObject(d["value"]),
-                              vertex)
-
-
-class PropertyDeserializer(_GraphSONTypeIO):
-    graphson_type = "g:Property"
-
-    @classmethod
-    def objectify(cls, d, reader):
-        element = reader.toObject(d["element"]) if "element" in d else None
-        return Property(d["key"], reader.toObject(d["value"]), element)
-
-
-class PathDeserializer(_GraphSONTypeIO):
-    graphson_type = "g:Path"
-
-    @classmethod
-    def objectify(cls, d, reader):
-        return Path(reader.toObject(d["labels"]), reader.toObject(d["objects"]))
-
-
-class TDeserializer(_GraphSONTypeIO):
-    graphson_type = "g:T"
-
-    @classmethod
-    def objectify(cls, d, reader):
-        return T[d]
-
-
-class DirectionIO(_GraphSONTypeIO):
-    graphson_type = "g:Direction"
-    graphson_base_type = "Direction"
-    python_type = Direction
-
-    @classmethod
-    def dictify(cls, d, writer):
-        return GraphSONUtil.typedValue(cls.graphson_base_type, d.name, "g")
-
-    @classmethod
-    def objectify(cls, d, reader):
-        return Direction[d]
-
-
-class TraversalMetricsDeserializer(_GraphSONTypeIO):
-    graphson_type = "g:TraversalMetrics"
-
-    @classmethod
-    def objectify(cls, d, reader):
-        return reader.toObject(d)
-
-
-class MetricsDeserializer(_GraphSONTypeIO):
-    graphson_type = "g:Metrics"
-
-    @classmethod
-    def objectify(cls, d, reader):
-        return reader.toObject(d)
diff --git a/gremlin-python/src/main/jython/radish/feature_steps.py b/gremlin-python/src/main/jython/radish/feature_steps.py
deleted file mode 100644
index 9d70abf..0000000
--- a/gremlin-python/src/main/jython/radish/feature_steps.py
+++ /dev/null
@@ -1,283 +0,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.
-#
-
-import json
-import re
-from gremlin_python.structure.graph import Path
-from gremlin_python.process.anonymous_traversal import traversal
-from gremlin_python.process.graph_traversal import __
-from gremlin_python.process.traversal import Barrier, Cardinality, P, TextP, Pop, Scope, Column, Order, Direction, T, Pick, Operator, IO, WithOptions
-from radish import given, when, then, world
-from hamcrest import *
-
-regex_all = re.compile(r"Pop\.all")
-regex_and = re.compile(r"([(.,\s])and\(")
-regex_as = re.compile(r"([(.,\s])as\(")
-regex_from = re.compile(r"([(.,\s])from\(")
-regex_global = re.compile(r"([(.,\s])global")
-regex_cardlist = re.compile(r"Cardinality\.list")
-regex_in = re.compile(r"([(.,\s])in\(")
-regex_is = re.compile(r"([(.,\s])is\(")
-regex_not = re.compile(r"([(.,\s])not\(")
-regex_or = re.compile(r"([(.,\s])or\(")
-regex_with = re.compile(r"([(.,\s])with\(")
-regex_true = re.compile(r"(true)")
-regex_false = re.compile(r"(false)")
-
-outV = __.outV
-label = __.label
-inV = __.inV
-project = __.project
-tail = __.tail
-
-ignores = []
-
-
-@given("the {graph_name:w} graph")
-def choose_graph(step, graph_name):
-    step.context.graph_name = graph_name
-    step.context.g = traversal().withRemote(step.context.remote_conn[graph_name])
-
-
-@given("the graph initializer of")
-def initialize_graph(step):
-    t = _make_traversal(step.context.g, step.text, {})
-
-    # just be sure that the traversal returns something to prove that it worked to some degree. probably
-    # is overkill to try to assert the complete success of this init operation. presumably the test
-    # suite would fail elsewhere if this didn't work which would help identify a problem.
-    result = t.toList()
-    assert len(result) > 0
-
-    # add the first result - if a map - to the bindings. this is useful for cases when parameters for
-    # the test traversal need to come from the original graph initializer (i.e. a new graph is created
-    # and you need the id of a vertex from that graph)
-
-
-@given("an unsupported test")
-def unsupported_scenario(step):
-    # this is a do nothing step as the test can't be supported for whatever reason
-    return
-
-
-@given("using the parameter {param_name:w} of P.{p_val:w}({param:QuotedString})")
-def add_p_parameter(step, param_name, p_val, param):
-    if not hasattr(step.context, "traversal_params"):
-        step.context.traversal_params = {}
-
-    step.context.traversal_params[param_name] = getattr(P, p_val)(_convert(param.replace('\\"', '"'), step.context))
-
-
-@given("using the parameter {param_name:w} defined as {param:QuotedString}")
-def add_parameter(step, param_name, param):
-    if not hasattr(step.context, "traversal_params"):
-        step.context.traversal_params = {}
-
-    step.context.traversal_params[param_name] = _convert(param.replace('\\"', '"'), step.context)
-
-
-@given("the traversal of")
-def translate_traversal(step):
-    step.context.ignore = ignores.__contains__(step.text)
-    step.context.traversal = _make_traversal(
-        step.context.g, step.text,
-        step.context.traversal_params if hasattr(step.context, "traversal_params") else {})
-
-
-@when("iterated to list")
-def iterate_the_traversal(step):
-    if step.context.ignore:
-        return
-    
-    step.context.result = map(lambda x: _convert_results(x), step.context.traversal.toList())
-
-
-@when("iterated next")
-def next_the_traversal(step):
-    if step.context.ignore:
-        return
-
-    step.context.result = map(lambda x: _convert_results(x), step.context.traversal.next())
-
-
-@then("the result should be {characterized_as:w}")
-def assert_result(step, characterized_as):
-    if step.context.ignore:
-        return
-
-    if characterized_as == "empty":        # no results
-        assert_that(len(step.context.result), equal_to(0))
-    elif characterized_as == "ordered":    # results asserted in the order of the data table
-        _table_assertion(step.table, step.context.result, step.context, True)
-    elif characterized_as == "unordered":  # results asserted in any order
-        _table_assertion(step.table, step.context.result, step.context, False)
-    elif characterized_as == "of":         # results may be of any of the specified items in the data table
-        _any_assertion(step.table, step.context.result, step.context)
-    else:
-        raise ValueError("unknown data characterization of " + characterized_as)
-
-
-@then("the graph should return {count:d} for count of {traversal_string:QuotedString}")
-def assert_side_effects(step, count, traversal_string):
-    if step.context.ignore:
-        return
-
-    t = _make_traversal(step.context.g, traversal_string.replace('\\"', '"'),
-                        step.context.traversal_params if hasattr(step.context, "traversal_params") else {})
-    assert_that(t.count().next(), equal_to(count))
-
-
-@then("the result should have a count of {count:d}")
-def assert_count(step, count):
-    assert_that(len(step.context.result), equal_to(count))
-
-
-@then("nothing should happen because")
-def nothing_happening(step):
-    return
-
-
-def _convert(val, ctx):
-    graph_name = ctx.graph_name
-    if isinstance(val, dict):                                           # convert dictionary keys/values
-        n = {}
-        for key, value in val.items():
-            n[_convert(key, ctx)] = _convert(value, ctx)
-        return n
-    elif isinstance(val, unicode):                                      # convert annoying python 2.x unicode nonsense
-        return _convert(val.encode('utf-8'), ctx)
-    elif isinstance(val, str) and re.match("^l\[.*\]$", val):           # parse list
-        return [] if val == "l[]" else list(map((lambda x: _convert(x, ctx)), val[2:-1].split(",")))
-    elif isinstance(val, str) and re.match("^s\[.*\]$", val):           # parse set
-        return set() if val == "s[]" else set(map((lambda x: _convert(x, ctx)), val[2:-1].split(",")))
-    elif isinstance(val, str) and re.match("^d\[.*\]\.[ilfdm]$", val):  # parse numeric
-        return float(val[2:-3]) if val[2:-3].__contains__(".") else long(val[2:-3])
-    elif isinstance(val, str) and re.match("^v\[.*\]\.id$", val):       # parse vertex id
-        return __find_cached_element(ctx, graph_name, val[2:-4], "v").id
-    elif isinstance(val, str) and re.match("^v\[.*\]\.sid$", val):      # parse vertex id as string
-        return str(__find_cached_element(ctx, graph_name, val[2:-5], "v").id)
-    elif isinstance(val, str) and re.match("^v\[.*\]$", val):           # parse vertex
-        return __find_cached_element(ctx, graph_name, val[2:-1], "v")
-    elif isinstance(val, str) and re.match("^e\[.*\]\.id$", val):       # parse edge id
-        return __find_cached_element(ctx, graph_name, val[2:-4], "e").id
-    elif isinstance(val, str) and re.match("^e\[.*\]\.sid$", val):      # parse edge id as string
-        return str(__find_cached_element(ctx, graph_name, val[2:-5], "e").id)
-    elif isinstance(val, str) and re.match("^e\[.*\]$", val):           # parse edge
-        return __find_cached_element(ctx, graph_name, val[2:-1], "e")
-    elif isinstance(val, str) and re.match("^m\[.*\]$", val):           # parse json as a map
-        return _convert(json.loads(val[2:-1]), ctx)
-    elif isinstance(val, str) and re.match("^p\[.*\]$", val):           # parse path
-        path_objects = list(map((lambda x: _convert(x, ctx)), val[2:-1].split(",")))
-        return Path([set([])], path_objects)
-    elif isinstance(val, str) and re.match("^c\[.*\]$", val):           # parse lambda/closure
-        return lambda: (val[2:-1], "gremlin-groovy")
-    elif isinstance(val, str) and re.match("^t\[.*\]$", val):           # parse instance of T enum
-        return T[val[2:-1]]
-    elif isinstance(val, str) and re.match("^D\[.*\]$", val):           # parse instance of Direction enum
-        return Direction[val[2:-1]]
-    else:
-        return val
-
-
-def __find_cached_element(ctx, graph_name, identifier, element_type):
-    if graph_name == "empty":
-        cache = world.create_lookup_v(ctx.remote_conn["empty"]) if element_type == "v" else world.create_lookup_e(ctx.remote_conn["empty"])
-    else:
-        cache = ctx.lookup_v[graph_name] if element_type == "v" else ctx.lookup_e[graph_name]
-
-    return cache[identifier]
-
-
-def _convert_results(val):
-    if isinstance(val, Path):
-        # kill out labels as they aren't in the assertion logic
-        return Path([set([])], map(lambda p: p.encode("utf-8") if isinstance(p, unicode) else p, val.objects))
-    else:
-        return val
-
-
-def _any_assertion(data, result, ctx):
-    converted = [_convert(line['result'], ctx) for line in data]
-    for r in result:
-        assert_that(r, is_in(converted))
-
-
-def _table_assertion(data, result, ctx, ordered):
-    # results from traversal should have the same number of entries as the feature data table
-    assert_that(len(result), equal_to(len(data)), "result:" + str(result))
-
-    results_to_test = list(result)
-
-    # finds a match in the results for each line of data to assert and then removes that item
-    # from the list - in the end there should be no items left over and each will have been asserted
-    for ix, line in enumerate(data):
-        val = _convert(line['result'], ctx)
-
-        # clear the labels since we don't define them in .feature files
-        if isinstance(val, Path):
-            val.labels = [set([])]
-
-        if ordered:
-            assert_that(results_to_test[ix], equal_to(val))
-        else:
-            assert_that(val, is_in(results_to_test))
-            results_to_test.remove(val)
-
-    if not ordered:
-        assert_that(len(results_to_test), is_(0))
-
-
-def _translate(traversal_):
-    replaced = traversal_.replace("\n", "")
-    replaced = regex_all.sub(r"Pop.all_", replaced)
-    replaced = regex_cardlist.sub(r"Cardinality.list_", replaced)
-    replaced = regex_and.sub(r"\1and_(", replaced)
-    replaced = regex_from.sub(r"\1from_(", replaced)
-    replaced = regex_global.sub(r"\1global_", replaced)
-    replaced = regex_as.sub(r"\1as_(", replaced)
-    replaced = regex_is.sub(r"\1is_(", replaced)
-    replaced = regex_not.sub(r"\1not_(", replaced)
-    replaced = regex_or.sub(r"\1or_(", replaced)
-    replaced = regex_in.sub(r"\1in_(", replaced)
-    replaced = regex_with.sub(r"\1with_(", replaced)
-    replaced = regex_true.sub(r"True", replaced)
-    return regex_false.sub(r"False", replaced)
-
-
-def _make_traversal(g, traversal_string, params):
-    b = {"g": g,
-         "__": __,
-         "Barrier": Barrier,
-         "Cardinality": Cardinality,
-         "Column": Column,
-         "Direction": Direction,
-         "Order": Order,
-         "P": P,
-         "TextP": TextP,
-         "IO": IO,
-         "Pick": Pick,
-         "Pop": Pop,
-         "Scope": Scope,
-         "Operator": Operator,
-         "T": T,
-         "WithOptions": WithOptions}
-
-    b.update(params)
-
-    return eval(_translate(traversal_string), b)
diff --git a/gremlin-python/src/main/jython/radish/terrain.py b/gremlin-python/src/main/jython/radish/terrain.py
deleted file mode 100644
index 201cb70..0000000
--- a/gremlin-python/src/main/jython/radish/terrain.py
+++ /dev/null
@@ -1,97 +0,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.
-#
-
-from gremlin_python.process.anonymous_traversal import traversal
-from gremlin_python.process.graph_traversal import __
-from gremlin_python.driver import serializer
-from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection
-from radish import before, after, world
-
-outV = __.outV
-label = __.label
-inV = __.inV
-project = __.project
-tail = __.tail
-
-
-@before.all
-def prepare_static_traversal_source(features, marker):
-    # as the various traversal sources for testing do not change their data, there is no need to re-create remotes
-    # and client side lookup data over and over. it can be created once for all tests and be reused.
-    cache = {}
-    for graph_name in (("modern", "gmodern"), ("classic", "gclassic"), ("crew", "gcrew"), ("grateful", "ggrateful"), ("sink", "gsink")):
-        cache[graph_name[0]] = {}
-        remote = __create_remote(graph_name[1])
-        cache[graph_name[0]]["remote_conn"] = __create_remote(graph_name[1])
-        cache[graph_name[0]]["lookup_v"] = world.create_lookup_v(remote)
-        cache[graph_name[0]]["lookup_e"] = world.create_lookup_e(remote)
-
-    # store the cache on the global context so that remotes can be shutdown cleanly at the end of the tests
-    world.cache = cache
-
-    # iterate each feature and apply the cached remotes/lookups to each scenario context so that they are
-    # accessible to the feature steps for test logic
-    for feature in features:
-        for scenario in feature.all_scenarios:
-            scenario.context.remote_conn = {}
-            scenario.context.lookup_v = {}
-            scenario.context.lookup_e = {}
-
-            for graph_name in ("modern", "classic", "crew", "grateful", "sink"):
-                scenario.context.remote_conn[graph_name] = cache[graph_name]["remote_conn"]
-                scenario.context.lookup_v[graph_name] = cache[graph_name]["lookup_v"]
-                scenario.context.lookup_e[graph_name] = cache[graph_name]["lookup_e"]
-
-            # setup the "empty" lookups as needed
-            scenario.context.lookup_v["empty"] = {}
-            scenario.context.lookup_e["empty"] = {}
-
-
-@before.each_scenario
-def prepare_traversal_source(scenario):
-    # some tests create data - create a fresh remote to the empty graph and clear that graph prior to each test
-    remote = __create_remote("ggraph")
-    scenario.context.remote_conn["empty"] = remote
-    g = traversal().withRemote(remote)
-    g.V().drop().iterate()
-
-
-@after.each_scenario
-def close_traversal_source(scenario):
-    scenario.context.remote_conn["empty"].close()
-
-
-@after.all
-def close_static_traversal_source(features, marker):
-    for key, value in world.cache.iteritems():
-        value["remote_conn"].close()
-
-
-def __create_remote(server_graph_name):
-    if not("serializer" in world.config.user_data):
-        raise ValueError('test configuration requires setting of --user-data="serializer={mime-type}"')
-
-    if world.config.user_data["serializer"] == "application/vnd.gremlin-v3.0+json":
-        s = serializer.GraphSONSerializersV3d0()
-    elif world.config.user_data["serializer"] == "application/vnd.graphbinary-v1.0":
-        s = serializer.GraphBinarySerializersV1()
-    else:
-        raise ValueError('serializer not found - ' + world.config.user_data["serializer"])
-
-    return DriverRemoteConnection('ws://localhost:45940/gremlin', server_graph_name, message_serializer=s)
diff --git a/gremlin-python/src/main/jython/radish/utils.py b/gremlin-python/src/main/jython/radish/utils.py
deleted file mode 100644
index 89e21b9..0000000
--- a/gremlin-python/src/main/jython/radish/utils.py
+++ /dev/null
@@ -1,40 +0,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.
-#
-
-from gremlin_python.process.anonymous_traversal import traversal
-from gremlin_python.process.graph_traversal import __
-from radish import pick
-
-@pick
-def create_lookup_v(remote):
-    g = traversal().withRemote(remote)
-
-    # hold a map of name/vertex for use in asserting results
-    return g.V().group().by('name').by(__.tail()).next()
-
-
-@pick
-def create_lookup_e(remote):
-    g = traversal().withRemote(remote)
-
-    # hold a map of the "name"/edge for use in asserting results - "name" in this context is in the form of
-    # outgoingV-label->incomingV
-    return g.E().group(). \
-        by(lambda: ("it.outVertex().value('name') + '-' + it.label() + '->' + it.inVertex().value('name')", "gremlin-groovy")). \
-        by(__.tail()).next()
diff --git a/gremlin-python/src/main/jython/setup.py b/gremlin-python/src/main/jython/setup.py
deleted file mode 100644
index ae4609d..0000000
--- a/gremlin-python/src/main/jython/setup.py
+++ /dev/null
@@ -1,93 +0,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.
-"""
-import codecs
-import os
-import sys
-import time
-from setuptools import setup
-
-# Folder containing the setup.py
-root = os.path.dirname(os.path.abspath(__file__))
-
-# Path to __version__ module
-version_file = os.path.join(root, 'gremlin_python', '__version__.py')
-
-# Check if this is a source distribution.
-# If not create the __version__ module containing the version
-if not os.path.exists(os.path.join(root, 'PKG-INFO')):
-    timestamp = int(os.getenv('TIMESTAMP', time.time() * 1000)) / 1000
-    fd = codecs.open(version_file, 'w', 'utf-8')
-    fd.write("'''")
-    fd.write(__doc__)
-    fd.write("'''\n")
-    fd.write('version   = %r\n' % os.getenv('VERSION', '?').replace('-SNAPSHOT', '.dev-%d' % timestamp))
-    fd.write('timestamp = %d\n' % timestamp)
-    fd.close()
-# Load version
-from gremlin_python import __version__
-
-version = __version__.version
-
-install_requires = [
-    'aenum>=1.4.5,<3.0.0',
-    'tornado>=4.4.1,<6.0',
-    'six>=1.10.0,<2.0.0',
-    'isodate>=0.6.0,<1.0.0',
-    'pyparsing>=2.4.7,<3.0.0'
-]
-
-if sys.version_info < (3, 2):
-    install_requires += ['futures>=3.0.5,<4.0.0']
-
-if sys.version_info < (3, 5):
-    install_requires += ['pyparsing>=2.4.6,<3.0.0']
-
-setup(
-    name='gremlinpython',
-    version=version,
-    packages=['gremlin_python', 'gremlin_python.driver',
-              'gremlin_python.driver.tornado', 'gremlin_python.process',
-              'gremlin_python.structure', 'gremlin_python.structure.io'],
-    license='Apache 2',
-    url='http://tinkerpop.apache.org',
-    description='Gremlin-Python for Apache TinkerPop',
-    long_description=codecs.open("README.rst", "r", "UTF-8").read(),
-    long_description_content_type='text/x-rst',
-    test_suite="tests",
-    data_files=[("", ["LICENSE", "NOTICE"])],
-    setup_requires=[
-        'pytest-runner==5.2',
-        'importlib-metadata<3.0.0'
-    ],
-    tests_require=[
-        'pytest>=4.6.4,<5.0.0',
-        'mock>=3.0.5,<4.0.0',
-        'radish-bdd==0.8.6',
-        'PyHamcrest>=1.9.0,<2.0.0'
-    ],
-    install_requires=install_requires,
-    classifiers=[
-        "Intended Audience :: Developers",
-        "License :: OSI Approved :: Apache Software License",
-        "Natural Language :: English",
-        "Programming Language :: Python :: 2.7",
-        "Programming Language :: Python :: 3.4",
-        "Programming Language :: Python :: 3.5",
-    ]
-)
diff --git a/gremlin-python/src/main/jython/tests/conftest.py b/gremlin-python/src/main/jython/tests/conftest.py
deleted file mode 100644
index 110c63c..0000000
--- a/gremlin-python/src/main/jython/tests/conftest.py
+++ /dev/null
@@ -1,144 +0,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.
-#
-import concurrent.futures
-import ssl
-import pytest
-import sys
-
-from six.moves import queue
-
-from gremlin_python.driver.client import Client
-from gremlin_python.driver.connection import Connection
-from gremlin_python.driver import serializer
-from gremlin_python.driver.driver_remote_connection import (
-    DriverRemoteConnection)
-from gremlin_python.driver.protocol import GremlinServerWSProtocol
-from gremlin_python.driver.serializer import (
-    GraphSONMessageSerializer, GraphSONSerializersV2d0, GraphSONSerializersV3d0,
-    GraphBinarySerializersV1)
-from gremlin_python.driver.tornado.transport import TornadoTransport
-
-# docker Gremlin Server = 172.17.0.2
-gremlin_server_host = "localhost"
-gremlin_server_url = 'ws://' + gremlin_server_host + ':45940/gremlin'
-
-
-@pytest.fixture
-def connection(request):
-    protocol = GremlinServerWSProtocol(
-        GraphSONMessageSerializer(),
-        username='stephen', password='password')
-    executor = concurrent.futures.ThreadPoolExecutor(5)
-    pool = queue.Queue()
-    try:
-        conn = Connection(gremlin_server_url, 'gmodern', protocol,
-                          lambda: TornadoTransport(), executor, pool)
-    except OSError:
-        executor.shutdown()
-        pytest.skip('Gremlin Server is not running')
-    else:
-        def fin():
-            executor.shutdown()
-            conn.close()
-        request.addfinalizer(fin)
-        return conn
-
-
-@pytest.fixture
-def client(request):
-    try:
-        client = Client(gremlin_server_url, 'gmodern')
-    except OSError:
-        pytest.skip('Gremlin Server is not running')
-    else:
-        def fin():
-            client.close()
-        request.addfinalizer(fin)
-        return client
-
-
-@pytest.fixture
-def secure_client(request):
-    try:
-        # turn off certificate verification for testing purposes only
-        ssl_opts = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
-        ssl_opts.verify_mode = ssl.CERT_NONE
-
-        client = Client('wss://' + gremlin_server_host + ':45941/gremlin', 'gmodern',
-                        username='stephen', password='password',
-                        transport_factory=lambda: TornadoTransport(ssl_options=ssl_opts))
-    except OSError:
-        pytest.skip('Gremlin Server is not running')
-    else:
-        def fin():
-            client.close()
-        request.addfinalizer(fin)
-        return client
-
-
-@pytest.fixture(params=['graphsonv2', 'graphsonv3', 'graphbinaryv1'])
-def remote_connection(request):
-    try:
-        if request.param == 'graphbinaryv1':
-            remote_conn = DriverRemoteConnection(gremlin_server_url, 'gmodern',
-                                                 message_serializer=serializer.GraphBinarySerializersV1())
-        elif request.param == 'graphsonv2':
-            remote_conn = DriverRemoteConnection(gremlin_server_url, 'gmodern',
-                                                 message_serializer=serializer.GraphSONSerializersV2d0())
-        elif request.param == 'graphsonv3':
-            remote_conn = DriverRemoteConnection(gremlin_server_url, 'gmodern',
-                                                 message_serializer=serializer.GraphSONSerializersV3d0())
-        else:
-            raise ValueError("Invalid serializer option - " + request.param)
-    except OSError:
-        pytest.skip('Gremlin Server is not running')
-    else:
-        def fin():
-            remote_conn.close()
-        request.addfinalizer(fin)
-        return remote_conn
-
-
-@pytest.fixture
-def remote_connection_v2(request):
-    try:
-        remote_conn = DriverRemoteConnection(gremlin_server_url, 'g',
-                                             message_serializer=serializer.GraphSONSerializersV2d0())
-    except OSError:
-        pytest.skip('Gremlin Server is not running')
-    else:
-        def fin():
-            remote_conn.close()
-        request.addfinalizer(fin)
-        return remote_conn
-
-
-@pytest.fixture
-def graphson_serializer_v2(request):
-    return GraphSONSerializersV2d0()
-
-
-@pytest.fixture
-def graphson_serializer_v3(request):
-    return GraphSONSerializersV3d0()
-
-
-@pytest.fixture
-def graphbinary_serializer_v1(request):
-    return GraphBinarySerializersV1()
diff --git a/gremlin-python/src/main/jython/tests/driver/test_client.py b/gremlin-python/src/main/jython/tests/driver/test_client.py
deleted file mode 100644
index bf85986..0000000
--- a/gremlin-python/src/main/jython/tests/driver/test_client.py
+++ /dev/null
@@ -1,350 +0,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.
-#
-import threading
-import uuid
-
-from gremlin_python.driver.client import Client
-from gremlin_python.driver.protocol import GremlinServerError
-from gremlin_python.driver.request import RequestMessage
-from gremlin_python.process.graph_traversal import __
-from gremlin_python.process.strategies import OptionsStrategy
-from gremlin_python.structure.graph import Graph
-from gremlin_python.driver.tornado.transport import TornadoTransport
-from tornado.util import TimeoutError
-
-__author__ = 'David M. Brown (davebshow@gmail.com)'
-
-
-def test_connection(connection):
-    g = Graph().traversal()
-    t = g.V()
-    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'gmodern'}})
-    results_set = connection.write(message).result()
-    future = results_set.all()
-    results = future.result()
-    assert len(results) == 6
-    assert isinstance(results, list)
-    assert results_set.done.done()
-    assert 'host' in results_set.status_attributes
-
-
-def test_client_message_too_big(client):
-    try:
-        client = Client("http://localhost", 'g', max_content_length=1024)
-        client.submit("1+1").all().result()
-        assert False
-    except Exception:
-        assert True
-    finally:
-        client.close()
-
-
-def test_client_simple_eval(client):
-    assert client.submit('1 + 1').all().result()[0] == 2
-
-
-def test_client_simple_eval_bindings(client):
-    assert client.submit('x + x', {'x': 2}).all().result()[0] == 4
-
-
-def test_client_eval_traversal(client):
-    assert len(client.submit('g.V()').all().result()) == 6
-
-
-def test_client_error(client):
-    try:
-        # should fire an exception
-        client.submit('1/0').all().result()
-        assert False
-    except GremlinServerError as ex:
-        assert 'exceptions' in ex.status_attributes
-        assert 'stackTrace' in ex.status_attributes
-
-
-def test_client_connection_pool_after_error(client):
-    # Overwrite fixture with pool_size=1 client
-    client = Client('ws://localhost:45940/gremlin', 'gmodern', pool_size=1)
-
-    try:
-        # should fire an exception
-        client.submit('1/0').all().result()
-        assert False
-    except GremlinServerError as gse:
-        # expecting the pool size to be 1 again after query returned
-        assert gse.status_code == 597
-        assert client.available_pool_size == 1
-
-
-def test_client_side_timeout_set_for_tornado(client):
-    client = Client('ws://localhost:45940/gremlin', 'gmodern',
-                    transport_factory=lambda: TornadoTransport(read_timeout=1, write_timeout=1))
-
-    try:
-        # should fire an exception
-        client.submit('Thread.sleep(2000);1').all().result()
-        assert False
-    except TimeoutError as toerr:
-        assert str(toerr) == "Operation timed out after 1 seconds"
-
-
-def test_client_bytecode(client):
-    g = Graph().traversal()
-    t = g.V()
-    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'gmodern'}})
-    result_set = client.submit(message)
-    assert len(result_set.all().result()) == 6
-
-
-def test_client_bytecode_options(client):
-    # smoke test to validate serialization of OptionsStrategy. no way to really validate this from an integration
-    # test perspective because there's no way to access the internals of the strategy via bytecode
-    g = Graph().traversal()
-    t = g.withStrategies(OptionsStrategy(options={"x": "test", "y": True})).V()
-    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'gmodern'}})
-    result_set = client.submit(message)
-    assert len(result_set.all().result()) == 6
-    ##
-    t = g.with_("x", "test").with_("y", True).V()
-    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'gmodern'}})
-    result_set = client.submit(message)
-    assert len(result_set.all().result()) == 6
-
-
-def test_iterate_result_set(client):
-    g = Graph().traversal()
-    t = g.V()
-    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'gmodern'}})
-    result_set = client.submit(message)
-    results = []
-    for result in result_set:
-        results += result
-    assert len(results) == 6
-
-
-def test_client_async(client):
-    g = Graph().traversal()
-    t = g.V()
-    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'gmodern'}})
-    future = client.submitAsync(message)
-    result_set = future.result()
-    assert len(result_set.all().result()) == 6
-
-
-def test_connection_share(client):
-    # Overwrite fixture with pool_size=1 client
-    client = Client('ws://localhost:45940/gremlin', 'gmodern', pool_size=1)
-    g = Graph().traversal()
-    t = g.V()
-    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'gmodern'}})
-    message2 = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'gmodern'}})
-    future = client.submitAsync(message)
-    future2 = client.submitAsync(message2)
-
-    result_set2 = future2.result()
-    assert len(result_set2.all().result()) == 6
-
-    # This future has to finish for the second to yield result - pool_size=1
-    assert future.done()
-    result_set = future.result()
-    assert len(result_set.all().result()) == 6
-
-
-def test_multi_conn_pool(client):
-    g = Graph().traversal()
-    t = g.V()
-    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'gmodern'}})
-    message2 = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'gmodern'}})
-    client = Client('ws://localhost:45940/gremlin', 'g', pool_size=1)
-    future = client.submitAsync(message)
-    future2 = client.submitAsync(message2)
-
-    result_set2 = future2.result()
-    assert len(result_set2.all().result()) == 6
-
-    # with connection pool `future` may or may not be done here
-    result_set = future.result()
-    assert len(result_set.all().result()) == 6
-
-
-def test_multi_thread_pool(client):
-    g = Graph().traversal()
-    traversals = [g.V(),
-                  g.V().count(),
-                  g.E(),
-                  g.E().count()
-                  ]
-    results = [[] for _ in traversals]
-
-    # Use a condition variable to synchronise a group of threads, which should also inject some
-    # non-determinism into the run-time execution order
-    condition = threading.Condition()
-
-    def thread_run(tr, result_list):
-        message = RequestMessage('traversal', 'bytecode', {'gremlin': tr.bytecode, 'aliases': {'g': 'gmodern'}})
-        with condition:
-            condition.wait(5)
-        result_set = client.submit(message)
-        for result in result_set:
-            result_list.append(result)
-
-    threads = []
-    for i in range(len(results)):
-        thread = threading.Thread(target=thread_run,
-                                  args=(traversals[i], results[i]),
-                                  name="test_multi_thread_pool_%d" % i)
-        thread.daemon = True
-        threads.append(thread)
-        thread.start()
-    with condition:
-        condition.notify_all()
-
-    for t in threads:
-        t.join(5)
-
-    assert len(results[0][0]) == 6
-    assert results[1][0][0].object == 6
-    assert len(results[2][0]) == 6
-    assert results[3][0][0].object == 6
-
-
-def test_client_bytecode_with_int(client):
-    g = Graph().traversal()
-    t = g.V().has('age', 851401972585122).count()
-    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'gmodern'}})
-    result_set = client.submit(message)
-    results = []
-    for result in result_set:
-        results += result
-    assert len(results) == 1
-
-
-def test_multi_request_in_session(client):
-    # Overwrite fixture with session client
-    session_id = str(uuid.uuid4())
-    client = Client('ws://localhost:45940/gremlin', 'g', session=session_id)
-
-    assert client.submit('x = 1').all().result()[0] == 1
-    assert client.submit('x + 2').all().result()[0] == 3
-
-    client.close()
-
-    # attempt reconnect to session and make sure "x" is no longer a thing
-    client = Client('ws://localhost:45940/gremlin', 'g', session=session_id)
-    try:
-        # should fire an exception
-        client.submit('x').all().result()
-        assert False
-    except Exception:
-        assert True
-
-
-def test_client_pool_in_session(client):
-    # Overwrite fixture with pool_size=2 client
-    try:
-        # should fire an exception
-        client = Client('ws://localhost:45940/gremlin', 'g', session=str(uuid.uuid4()), pool_size=2)
-        assert False
-    except Exception:
-        assert True
-
-
-def test_big_result_set(client):
-    g = Graph().traversal()
-    t = g.inject(1).repeat(__.addV('person').property('name', __.loops())).times(20000).count()
-    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'g'}})
-    result_set = client.submit(message)
-    results = []
-    for result in result_set:
-        results += result
-    assert len(results) == 1
-
-    t = g.V().limit(10)
-    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'g'}})
-    result_set = client.submit(message)
-    results = []
-    for result in result_set:
-        results += result
-    assert len(results) == 10
-
-    t = g.V().limit(100)
-    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'g'}})
-    result_set = client.submit(message)
-    results = []
-    for result in result_set:
-        results += result
-    assert len(results) == 100
-
-    t = g.V().limit(1000)
-    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'g'}})
-    result_set = client.submit(message)
-    results = []
-    for result in result_set:
-        results += result
-    assert len(results) == 1000
-
-    t = g.V().limit(10000)
-    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'g'}})
-    result_set = client.submit(message)
-    results = []
-    for result in result_set:
-        results += result
-    assert len(results) == 10000
-
-
-def test_big_result_set_secure(secure_client):
-    g = Graph().traversal()
-    t = g.inject(1).repeat(__.addV('person').property('name', __.loops())).times(20000).count()
-    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'g'}})
-    result_set = secure_client.submit(message)
-    results = []
-    for result in result_set:
-        results += result
-    assert len(results) == 1
-
-    t = g.V().limit(10)
-    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'g'}})
-    result_set = secure_client.submit(message)
-    results = []
-    for result in result_set:
-        results += result
-    assert len(results) == 10
-
-    t = g.V().limit(100)
-    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'g'}})
-    result_set = secure_client.submit(message)
-    results = []
-    for result in result_set:
-        results += result
-    assert len(results) == 100
-
-    t = g.V().limit(1000)
-    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'g'}})
-    result_set = secure_client.submit(message)
-    results = []
-    for result in result_set:
-        results += result
-    assert len(results) == 1000
-
-    t = g.V().limit(10000)
-    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'g'}})
-    result_set = secure_client.submit(message)
-    results = []
-    for result in result_set:
-        results += result
-    assert len(results) == 10000
diff --git a/gremlin-python/src/main/jython/tests/driver/test_driver_remote_connection.py b/gremlin-python/src/main/jython/tests/driver/test_driver_remote_connection.py
deleted file mode 100644
index c579410..0000000
--- a/gremlin-python/src/main/jython/tests/driver/test_driver_remote_connection.py
+++ /dev/null
@@ -1,320 +0,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.
-#
-import pytest
-
-from tornado import ioloop, gen
-
-from gremlin_python import statics
-from gremlin_python.driver.protocol import GremlinServerError
-from gremlin_python.statics import long
-from gremlin_python.driver.driver_remote_connection import (
-    DriverRemoteConnection)
-from gremlin_python.process.traversal import Traverser
-from gremlin_python.process.traversal import TraversalStrategy
-from gremlin_python.process.traversal import Bindings
-from gremlin_python.process.traversal import P
-from gremlin_python.process.graph_traversal import __
-from gremlin_python.process.anonymous_traversal import traversal
-from gremlin_python.structure.graph import Vertex
-from gremlin_python.process.strategies import SubgraphStrategy, ReservedKeysVerificationStrategy
-
-__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
-
-
-class TestDriverRemoteConnection(object):
-    def test_traversals(self, remote_connection):
-        statics.load_statics(globals())
-        g = traversal().withRemote(remote_connection)
-
-        assert long(6) == g.V().count().toList()[0]
-        # #
-        assert Vertex(1) == g.V(1).next()
-        assert 1 == g.V(1).id().next()
-        assert Traverser(Vertex(1)) == g.V(1).nextTraverser()
-        assert 1 == len(g.V(1).toList())
-        assert isinstance(g.V(1).toList(), list)
-        results = g.V().repeat(out()).times(2).name
-        results = results.toList()
-        assert 2 == len(results)
-        assert "lop" in results
-        assert "ripple" in results
-        # #
-        assert 10 == g.V().repeat(both()).times(5)[0:10].count().next()
-        assert 1 == g.V().repeat(both()).times(5)[0:1].count().next()
-        assert 0 == g.V().repeat(both()).times(5)[0:0].count().next()
-        assert 4 == g.V()[2:].count().next()
-        assert 2 == g.V()[:2].count().next()
-        # #
-        results = g.withSideEffect('a', ['josh', 'peter']).V(1).out('created').in_('created').values('name').where(P.within('a')).toList()
-        assert 2 == len(results)
-        assert 'josh' in results
-        assert 'peter' in results
-        # #
-        results = g.V().out().profile().toList()
-        assert 1 == len(results)
-        assert 'metrics' in results[0]
-        assert 'dur' in results[0]
-        # #
-        results = g.V().has('name', 'peter').as_('a').out('created').as_('b').select('a', 'b').by(
-            __.valueMap()).toList()
-        assert 1 == len(results)
-        assert 'peter' == results[0]['a']['name'][0]
-        assert 35 == results[0]['a']['age'][0]
-        assert 'lop' == results[0]['b']['name'][0]
-        assert 'java' == results[0]['b']['lang'][0]
-        assert 2 == len(results[0]['a'])
-        assert 2 == len(results[0]['b'])
-        # #
-        results = g.V(1).inject(g.V(2).next()).values('name').toList()
-        assert 2 == len(results)
-        assert 'marko' in results
-        assert 'vadas' in results
-        # #
-        results = g.V().has('person', 'name', 'marko').map(lambda: ("it.get().value('name')", "gremlin-groovy")).toList()
-        assert 1 == len(results)
-        assert 'marko' in results
-        # #
-        # this test just validates that the underscored versions of steps conflicting with Gremlin work
-        # properly and can be removed when the old steps are removed - TINKERPOP-2272
-        results = g.V().filter_(__.values('age').sum_().and_(
-            __.max_().is_(gt(0)), __.min_().is_(gt(0)))).range_(0, 1).id_().next()
-        assert 1 == results
-        # #
-        # test binding in P
-        results = g.V().has('person', 'age', Bindings.of('x', lt(30))).count().next()
-        assert 2 == results
-
-    def test_lambda_traversals(self, remote_connection):
-        statics.load_statics(globals())
-        assert "remoteconnection[ws://localhost:45940/gremlin,gmodern]" == str(remote_connection)
-        g = traversal().withRemote(remote_connection)
-
-        assert 24.0 == g.withSack(1.0, lambda: ("x -> x + 1", "gremlin-groovy")).V().both().sack().sum().next()
-        assert 24.0 == g.withSack(lambda: ("{1.0d}", "gremlin-groovy"), lambda: ("x -> x + 1", "gremlin-groovy")).V().both().sack().sum().next()
-
-        assert 48.0 == g.withSack(1.0, lambda: ("x, y ->  x + y + 1", "gremlin-groovy")).V().both().sack().sum().next()
-        assert 48.0 == g.withSack(lambda: ("{1.0d}", "gremlin-groovy"), lambda: ("x, y ->  x + y + 1", "gremlin-groovy")).V().both().sack().sum().next()
-
-    def test_iteration(self, remote_connection):
-        statics.load_statics(globals())
-        g = traversal().withRemote(remote_connection)
-
-        t = g.V().count()
-        assert t.hasNext()
-        assert t.hasNext()
-        assert t.hasNext()
-        assert t.hasNext()
-        assert t.hasNext()
-        assert 6 == t.next()
-        assert not(t.hasNext())
-        assert not(t.hasNext())
-        assert not(t.hasNext())
-        assert not(t.hasNext())
-        assert not(t.hasNext())
-
-        t = g.V().has('name', P.within('marko', 'peter')).values('name').order()
-        assert "marko" == t.next()
-        assert t.hasNext()
-        assert t.hasNext()
-        assert t.hasNext()
-        assert t.hasNext()
-        assert t.hasNext()
-        assert "peter" == t.next()
-        assert not(t.hasNext())
-        assert not(t.hasNext())
-        assert not(t.hasNext())
-        assert not(t.hasNext())
-        assert not(t.hasNext())
-
-        try:
-            t.next()
-            assert False
-        except StopIteration:
-            assert True
-
-    def test_strategies(self, remote_connection):
-        statics.load_statics(globals())
-        g = traversal().withRemote(remote_connection). \
-            withStrategies(TraversalStrategy("SubgraphStrategy",
-                                             {"vertices": __.hasLabel("person"),
-                                              "edges": __.hasLabel("created")},
-                                              "org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy"))
-        assert 4 == g.V().count().next()
-        assert 0 == g.E().count().next()
-        assert 1 == g.V().label().dedup().count().next()
-        assert 4 == g.V().filter(lambda: ("lambda x: True", "gremlin-python")).count().next()
-        assert "person" == g.V().label().dedup().next()
-        #
-        g = traversal().withRemote(remote_connection). \
-            withStrategies(SubgraphStrategy(vertices=__.hasLabel("person"), edges=__.hasLabel("created")))
-        assert 4 == g.V().count().next()
-        assert 0 == g.E().count().next()
-        assert 1 == g.V().label().dedup().count().next()
-        assert "person" == g.V().label().dedup().next()
-        #
-        g = traversal().withRemote(remote_connection). \
-            withStrategies(SubgraphStrategy(edges=__.hasLabel("created")))
-        assert 6 == g.V().count().next()
-        assert 4 == g.E().count().next()
-        assert 1 == g.E().label().dedup().count().next()
-        assert "created" == g.E().label().dedup().next()
-        #
-        g = g.withoutStrategies(SubgraphStrategy). \
-            withComputer(vertices=__.has("name", "marko"), edges=__.limit(0))
-        assert 1 == g.V().count().next()
-        assert 0 == g.E().count().next()
-        assert "person" == g.V().label().next()
-        assert "marko" == g.V().name.next()
-        #
-        g = traversal().withRemote(remote_connection).withComputer()
-        assert 6 == g.V().count().next()
-        assert 6 == g.E().count().next()
-        #
-        g = traversal().withRemote(remote_connection). \
-            withStrategies(ReservedKeysVerificationStrategy(throw_exception=True))
-        try:
-            g.addV("person").property("id", "please-don't-use-id").iterate()
-            assert False
-        except GremlinServerError as gse:
-            assert gse.status_code == 500
-        #
-        g = traversal().withRemote(remote_connection).with_("x", True).with_('evaluationTimeout', 10)
-        try:
-            g.inject(1).sideEffect(lambda: ("Thread.sleep(5000)", "gremlin-groovy")).iterate()
-            assert False
-        except GremlinServerError as gse:
-            assert gse.status_code == 598
-
-    def test_side_effects(self, remote_connection):
-        statics.load_statics(globals())
-        #
-        g = traversal().withRemote(remote_connection)
-        ###
-        t = g.V().hasLabel("project").name.iterate()
-        assert 0 == len(t.side_effects.keys())
-        with pytest.raises(Exception):
-            m = t.side_effects["m"]
-        ###
-        t = g.V().out("created").groupCount("m").by("name")
-        results = t.toSet()
-        assert 2 == len(results)
-        assert Vertex(3) in results
-        assert Vertex(5) in results
-        assert 1 == len(t.side_effects.keys())
-        assert "m" in t.side_effects.keys()
-        m = t.side_effects["m"]
-        assert isinstance(m, dict)
-        assert 2 == len(m)
-        assert 3 == m["lop"]
-        assert 1 == m["ripple"]
-
-        # check status attributes
-        assert "host" in t.side_effects.status_attributes
-
-        ##
-        t = g.V().out("created").groupCount("m").by("name").name.aggregate("n")
-        results = t.toSet()
-        assert 2 == len(results)
-        assert "lop" in results
-        assert "ripple" in results
-        assert 2 == len(t.side_effects.keys())
-        assert "m" in t.side_effects.keys()
-        assert "n" in t.side_effects.keys()
-        n = t.side_effects.get("n")
-        assert isinstance(n, dict)
-        assert 2 == len(n)
-        assert "lop" in n.keys()
-        assert "ripple" in n.keys()
-        assert 3 == n["lop"]
-        assert 1 == n["ripple"]
-
-        t = g.withSideEffect('m', 32).V().map(lambda: "x: x.sideEffects('m')")
-        results = t.toSet()
-        assert 1 == len(results)
-        assert 32 == list(results)[0]
-        assert 32 == t.side_effects['m']
-        assert 1 == len(t.side_effects.keys())
-        with pytest.raises(Exception):
-            x = t.side_effects["x"]
-
-        a = g.V().has("name", "marko").next()
-        b = g.V().has("name", "peter").next()
-        edge = g.withSideEffect("b", b).V(a).addE("knows").to("b").next()
-        assert "knows" == edge.label
-        assert a == edge.outV
-        assert b == edge.inV
-        g.V().has("name", "marko").outE("knows").where(__.inV().has("name", "peter")).drop().iterate()
-        ##
-        edge = g.withSideEffect("a", a).withSideEffect("b", b).V().limit(1).addE("knows").from_("a").to("b").next()
-        assert "knows" == edge.label
-        assert a == edge.outV
-        assert b == edge.inV
-        g.V().has("name", "marko").outE("knows").where(__.inV().has("name", "peter")).drop().iterate()
-
-    def test_side_effect_close(self, remote_connection):
-        g = traversal().withRemote(remote_connection)
-        t = g.V().aggregate('a').aggregate('b')
-        t.toList()
-
-        # The 'a' key should return some side effects
-        results = t.side_effects.get('a')
-        assert results
-
-        # Close result is None
-        results = t.side_effects.close()
-        assert not results
-
-        # Shouldn't get any new info from server
-        # 'b' isn't in local cache
-        results = t.side_effects.get('b')
-        assert not results
-
-        # But 'a' should still be cached locally
-        results = t.side_effects.get('a')
-        assert results
-
-        # 'a' should have been added to local keys cache, but not 'b'
-        results = t.side_effects.keys()
-        assert len(results) == 1
-        a, = results
-        assert a == 'a'
-
-        # Try to get 'b' directly from server, should throw error
-        with pytest.raises(Exception):
-            t.side_effects.value_lambda('b')
-
-    def test_promise(self, remote_connection):
-        g = traversal().withRemote(remote_connection)
-        future = g.V().aggregate('a').promise()
-        t = future.result()
-        assert len(t.toList()) == 6
-        a, = t.side_effects.keys()
-        assert a == 'a'
-        results = t.side_effects.get('a')
-        assert results
-        results = t.side_effects.close()
-        assert not results
-
-    def test_clone(self, remote_connection):
-        g = traversal().withRemote(remote_connection)
-        t = g.V().both()
-        assert 12 == len(t.toList())
-        assert 5 == t.clone().limit(5).count().next()
-        assert 10 == t.clone().limit(10).count().next()
-
diff --git a/gremlin-python/src/main/jython/tests/driver/test_driver_remote_connection_threaded.py b/gremlin-python/src/main/jython/tests/driver/test_driver_remote_connection_threaded.py
deleted file mode 100644
index 65b121d..0000000
--- a/gremlin-python/src/main/jython/tests/driver/test_driver_remote_connection_threaded.py
+++ /dev/null
@@ -1,74 +0,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.
-#
-import sys
-from threading import Thread
-from six.moves import queue
-
-from gremlin_python.driver.driver_remote_connection import (
-    DriverRemoteConnection)
-from gremlin_python.process.anonymous_traversal import traversal
-
-__author__ = 'David M. Brown (davebshow@gmail.com)'
-
-
-def test_conns_in_threads(remote_connection):
-    q = queue.Queue()
-    child = Thread(target=_executor, args=(q, None))
-    child2 = Thread(target=_executor, args=(q, None))
-    child.start()
-    child2.start()
-    for x in range(2):
-        success = q.get()
-        assert success == 'success!'
-    child.join()
-    child2.join()
-
-
-def test_conn_in_threads(remote_connection):
-    q = queue.Queue()
-    child = Thread(target=_executor, args=(q, remote_connection))
-    child2 = Thread(target=_executor, args=(q, remote_connection))
-    child.start()
-    child2.start()
-    for x in range(2):
-        success = q.get()
-        assert success == 'success!'
-    child.join()
-    child2.join()
-
-
-def _executor(q, conn):
-    close = False
-    if not conn:
-        # This isn't a fixture so close manually
-        close = True
-        conn = DriverRemoteConnection(
-            'ws://localhost:45940/gremlin', 'gmodern', pool_size=4)
-    try:
-        g = traversal().withRemote(conn)
-        future = g.V().promise()
-        t = future.result()
-        assert len(t.toList()) == 6
-    except:
-        q.put(sys.exc_info()[0])
-    else:
-        q.put('success!')
-        # Close conn
-        if close:
-            conn.close()
diff --git a/gremlin-python/src/main/jython/tests/process/test_traversal.py b/gremlin-python/src/main/jython/tests/process/test_traversal.py
deleted file mode 100644
index f2c1682..0000000
--- a/gremlin-python/src/main/jython/tests/process/test_traversal.py
+++ /dev/null
@@ -1,125 +0,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.
-#
-
-__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
-
-from pytest import fail
-
-from gremlin_python.structure.graph import Graph
-from gremlin_python.process.anonymous_traversal import traversal
-from gremlin_python.process.traversal import P
-from gremlin_python.process.traversal import Binding, Bindings
-from gremlin_python.process.graph_traversal import __
-
-
-class TestTraversal(object):
-    def test_bytecode(self):
-        g = traversal().withGraph(Graph())
-        bytecode = g.V().out("created").bytecode
-        assert 0 == len(bytecode.bindings.keys())
-        assert 0 == len(bytecode.source_instructions)
-        assert 2 == len(bytecode.step_instructions)
-        assert "V" == bytecode.step_instructions[0][0]
-        assert "out" == bytecode.step_instructions[1][0]
-        assert "created" == bytecode.step_instructions[1][1]
-        assert 1 == len(bytecode.step_instructions[0])
-        assert 2 == len(bytecode.step_instructions[1])
-        ##
-        bytecode = g.withSack(1).E().groupCount().by("weight").bytecode
-        assert 0 == len(bytecode.bindings.keys())
-        assert 1 == len(bytecode.source_instructions)
-        assert "withSack" == bytecode.source_instructions[0][0]
-        assert 1 == bytecode.source_instructions[0][1]
-        assert 3 == len(bytecode.step_instructions)
-        assert "E" == bytecode.step_instructions[0][0]
-        assert "groupCount" == bytecode.step_instructions[1][0]
-        assert "by" == bytecode.step_instructions[2][0]
-        assert "weight" == bytecode.step_instructions[2][1]
-        assert 1 == len(bytecode.step_instructions[0])
-        assert 1 == len(bytecode.step_instructions[1])
-        assert 2 == len(bytecode.step_instructions[2])
-        ##
-        bytecode = g.V(Bindings.of('a', [1,2,3])) \
-            .out(Bindings.of('b','created')) \
-            .where(__.in_(Bindings.of('c','created'), Bindings.of('d','knows')) \
-            .count().is_(Bindings.of('e',P.gt(2)))).bytecode
-        assert 5 == len(bytecode.bindings.keys())
-        assert [1,2,3] == bytecode.bindings['a']
-        assert 'created' == bytecode.bindings['b']
-        assert 'created' == bytecode.bindings['c']
-        assert 'knows' == bytecode.bindings['d']
-        assert P.gt(2) == bytecode.bindings['e']
-        assert Binding('b','created') == bytecode.step_instructions[1][1]
-        assert 'binding[b=created]' == str(bytecode.step_instructions[1][1])
-        assert isinstance(hash(bytecode.step_instructions[1][1]),int)
-
-    def test_P(self):
-        # verify that the order of operations is respected
-        assert "and(eq(a),lt(b))" == str(P.eq("a").and_(P.lt("b")))
-        assert "and(or(lt(b),gt(c)),neq(d))" == str(P.lt("b").or_(P.gt("c")).and_(P.neq("d")))
-        assert "and(or(lt(b),gt(c)),or(neq(d),gte(e)))" == str(
-            P.lt("b").or_(P.gt("c")).and_(P.neq("d").or_(P.gte("e"))))
-
-    def test_anonymous_traversal(self):
-        bytecode = __.__(1).bytecode
-        assert 0 == len(bytecode.bindings.keys())
-        assert 0 == len(bytecode.source_instructions)
-        assert 1 == len(bytecode.step_instructions)
-        assert "inject" == bytecode.step_instructions[0][0]
-        assert 1 == bytecode.step_instructions[0][1]
-        ##
-        bytecode = __.start().bytecode
-        assert 0 == len(bytecode.bindings.keys())
-        assert 0 == len(bytecode.source_instructions)
-        assert 0 == len(bytecode.step_instructions)
-
-    def test_clone_traversal(self):
-        g = traversal().withGraph(Graph())
-        original = g.V().out("created")
-        clone = original.clone().out("knows")
-        cloneClone = clone.clone().out("created")
-
-        assert 2 == len(original.bytecode.step_instructions)
-        assert 3 == len(clone.bytecode.step_instructions)
-        assert 4 == len(cloneClone.bytecode.step_instructions)
-
-        original.has("person", "name", "marko")
-        clone.V().out()
-
-        assert 3 == len(original.bytecode.step_instructions)
-        assert 5 == len(clone.bytecode.step_instructions)
-        assert 4 == len(cloneClone.bytecode.step_instructions)
-
-    def test_no_sugar_for_magic_methods(self):
-        g = traversal().withGraph(Graph())
-
-        t = g.V().age
-        assert 2 == len(t.bytecode.step_instructions)
-
-        try:
-            t = g.V().__len__
-            fail("can't do sugar with magic")
-        except AttributeError as err:
-            assert str(err) == 'Python magic methods or keys starting with double underscore cannot be used for Gremlin sugar - prefer values(__len__)'
-
-
-
-
-
-
diff --git a/gremlin-python/src/main/jython/tests/structure/io/test_functionalityio.py b/gremlin-python/src/main/jython/tests/structure/io/test_functionalityio.py
deleted file mode 100644
index 26a62a2..0000000
--- a/gremlin-python/src/main/jython/tests/structure/io/test_functionalityio.py
+++ /dev/null
@@ -1,97 +0,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.
-'''
-
-import datetime
-import uuid
-
-from gremlin_python.driver.serializer import GraphSONSerializersV2d0
-from gremlin_python.structure.graph import Graph
-from gremlin_python.statics import *
-
-
-def test_timestamp(remote_connection):
-    g = Graph().traversal().withRemote(remote_connection)
-    ts = timestamp(1481750076295 / 1000)
-    resp = g.addV('test_vertex').property('ts', ts)
-    resp = resp.toList()
-    vid = resp[0].id
-    try:
-        ts_prop = g.V(vid).properties('ts').toList()[0]
-        assert isinstance(ts_prop.value, timestamp)
-        assert ts_prop.value == ts
-    finally:
-        g.V(vid).drop().iterate()
-
-
-def test_datetime(remote_connection):
-    g = Graph().traversal().withRemote(remote_connection)
-    dt = datetime.datetime.utcfromtimestamp(1481750076295 / 1000)
-    resp = g.addV('test_vertex').property('dt', dt).toList()
-    vid = resp[0].id
-    try:
-        dt_prop = g.V(vid).properties('dt').toList()[0]
-        assert isinstance(dt_prop.value, datetime.datetime)
-        assert dt_prop.value == dt
-    finally:
-        g.V(vid).drop().iterate()
-
-
-def test_uuid(remote_connection):
-    g = Graph().traversal().withRemote(remote_connection)
-    uid = uuid.UUID("41d2e28a-20a4-4ab0-b379-d810dede3786")
-    resp = g.addV('test_vertex').property('uuid', uid).toList()
-    vid = resp[0].id
-    try:
-        uid_prop = g.V(vid).properties('uuid').toList()[0]
-        assert isinstance(uid_prop.value, uuid.UUID)
-        assert uid_prop.value == uid
-    finally:
-        g.V(vid).drop().iterate()
-
-
-def test_odd_bits(remote_connection):
-    if not isinstance(remote_connection._client._message_serializer, GraphSONSerializersV2d0):
-        g = Graph().traversal().withRemote(remote_connection)
-        char_lower = str.__new__(SingleChar, chr(78))
-        resp = g.addV('test_vertex').property('char_lower', char_lower).toList()
-        vid = resp[0].id
-        try:
-            v = g.V(vid).values('char_lower').toList()[0]
-            assert v == char_lower
-        finally:
-            g.V(vid).drop().iterate()
-
-        if six.PY3:
-            char_upper = str.__new__(SingleChar, chr(57344))
-            resp = g.addV('test_vertex').property('char_upper', char_upper).toList()
-            vid = resp[0].id
-            try:
-                v = g.V(vid).values('char_upper').toList()[0]
-                assert v == char_upper
-            finally:
-                g.V(vid).drop().iterate()
-                
-        dur = datetime.timedelta(seconds=1000, microseconds=1000)
-        resp = g.addV('test_vertex').property('dur', dur).toList()
-        vid = resp[0].id
-        try:
-            v = g.V(vid).values('dur').toList()[0]
-            assert v == dur
-        finally:
-            g.V(vid).drop().iterate()
diff --git a/gremlin-python/src/main/jython/tests/structure/io/test_graphbinaryV1.py b/gremlin-python/src/main/jython/tests/structure/io/test_graphbinaryV1.py
deleted file mode 100644
index a2320bc..0000000
--- a/gremlin-python/src/main/jython/tests/structure/io/test_graphbinaryV1.py
+++ /dev/null
@@ -1,215 +0,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.
-"""
-
-import datetime
-import calendar
-import time
-import uuid
-import math
-from decimal import *
-
-from mock import Mock
-
-import six
-
-from gremlin_python.statics import timestamp, long, SingleByte, SingleChar, ByteBufferType
-from gremlin_python.structure.graph import Vertex, Edge, Property, VertexProperty, Graph, Path
-from gremlin_python.structure.io.graphbinaryV1 import GraphBinaryWriter, GraphBinaryReader, DataType
-from gremlin_python.process.traversal import P, Barrier, Binding, Bytecode
-from gremlin_python.process.strategies import SubgraphStrategy
-from gremlin_python.process.graph_traversal import __
-
-
-class TestGraphBinaryReader(object):
-    graphbinary_reader = GraphBinaryReader()
-
-
-class TestGraphSONWriter(object):
-    graphbinary_writer = GraphBinaryWriter()
-    graphbinary_reader = GraphBinaryReader()
-
-    def test_int(self):
-        x = 100
-        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-        assert x == output
-
-    def test_long(self):
-        x = long(100)
-        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-        assert x == output
-
-    def test_float(self):
-        x = float(100.001)
-        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-        assert x == output
-
-        x = float('nan')
-        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-        assert math.isnan(output)
-
-        x = float('-inf')
-        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-        assert math.isinf(output) and output < 0
-
-        x = float('inf')
-        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-        assert math.isinf(output) and output > 0
-
-    def test_double(self):
-        x = 100.001
-        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-        assert x == output
-
-    def test_date(self):
-        x = datetime.datetime(2016, 12, 14, 16, 14, 36, 295000)
-        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-        assert x == output
-
-    def test_timestamp(self):
-        x = timestamp(1481750076295 / 1000)
-        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-        assert x == output
-
-    def test_string(self):
-        x = "serialize this!"
-        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-        assert x == output
-
-    def test_homogeneous_list(self):
-        x = ["serialize this!", "serialize that!", "serialize that!","stop telling me what to serialize"]
-        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-        assert x == output
-
-    def test_heterogeneous_list(self):
-        x = ["serialize this!", 0, "serialize that!", "serialize that!", 1, "stop telling me what to serialize", 2]
-        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-        assert x == output
-
-    def test_homogeneous_set(self):
-        x = {"serialize this!", "serialize that!", "stop telling me what to serialize"}
-        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-        assert x == output
-
-    def test_heterogeneous_set(self):
-        x = {"serialize this!", 0, "serialize that!", 1, "stop telling me what to serialize", 2}
-        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-        assert x == output
-
-    def test_dict(self):
-        x = {"yo": "what?",
-             "go": "no!",
-             "number": 123,
-             321: "crazy with the number for a key",
-             987: ["go", "deep", {"here": "!"}]}
-        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-        assert x == output
-
-        x = {"marko": [666], "noone": ["blah"]}
-        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-        assert x == output
-
-        x = {"ripple": [], "peter": ["created"], "noone": ["blah"], "vadas": [],
-             "josh": ["created", "created"], "lop": [], "marko": [666, "created", "knows", "knows"]}
-        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-        assert x == output
-
-    def test_uuid(self):
-        x = uuid.UUID("41d2e28a-20a4-4ab0-b379-d810dede3786")
-        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-        assert x == output
-
-    def test_edge(self):
-        x = Edge(123, Vertex(1, 'person'), "developed", Vertex(10, "software"))
-        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-        assert x == output
-        assert x.inV == output.inV
-        assert x.outV == output.outV
-
-    def test_path(self):
-        x = Path(["x", "y", "z"], [1, 2, 3])
-        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-        assert x == output
-
-    def test_property(self):
-        x = Property("name", "stephen", None)
-        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-        assert x == output
-
-    def test_vertex(self):
-        x = Vertex(123, "person")
-        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-        assert x == output
-
-    def test_vertexproperty(self):
-        x = VertexProperty(123, "name", "stephen", None)
-        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-        assert x == output
-        
-    def test_barrier(self):
-        x = Barrier.normSack
-        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-        assert x == output
-
-    def test_binding(self):
-        x = Binding("name", "marko")
-        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-        assert x == output
-
-    def test_bytecode(self):
-        x = Bytecode()
-        x.source_instructions.append(["withStrategies", "SubgraphStrategy"])
-        x.step_instructions.append(["V", 1, 2, 3])
-        x.step_instructions.append(["out"])
-        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-        assert x == output
-
-    def test_byte(self):
-        x = int.__new__(SingleByte, 1)
-        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-        assert x == output
-
-    def test_bytebuffer(self):
-        x = ByteBufferType("c29tZSBieXRlcyBmb3IgeW91", "utf8")
-        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-        assert x == output
-
-    def test_boolean(self):
-        x = True
-        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-        assert x == output
-
-        x = False
-        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-        assert x == output
-
-    def test_char(self):
-        x = str.__new__(SingleChar, chr(76))
-        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-        assert x == output
-
-        if six.PY3:
-            x = str.__new__(SingleChar, chr(57344))
-            output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-            assert x == output
-
-    def test_duration(self):
-        x = datetime.timedelta(seconds=1000, microseconds=1000)
-        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
-        assert x == output
-        
diff --git a/gremlin-python/src/main/jython/tests/structure/io/test_graphsonV2d0.py b/gremlin-python/src/main/jython/tests/structure/io/test_graphsonV2d0.py
deleted file mode 100644
index c06d57c..0000000
--- a/gremlin-python/src/main/jython/tests/structure/io/test_graphsonV2d0.py
+++ /dev/null
@@ -1,514 +0,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.
-#
-
-__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
-
-import datetime
-import calendar
-import json
-import uuid
-import math
-from decimal import *
-
-from mock import Mock
-
-from gremlin_python.statics import *
-from gremlin_python.structure.graph import Vertex, Edge, Property, VertexProperty, Graph, Path
-from gremlin_python.structure.io.graphsonV2d0 import GraphSONWriter, GraphSONReader, GraphSONUtil
-import gremlin_python.structure.io.graphsonV2d0
-from gremlin_python.process.traversal import P
-from gremlin_python.process.strategies import SubgraphStrategy
-from gremlin_python.process.graph_traversal import __
-
-
-class TestGraphSONReader(object):
-    graphson_reader = GraphSONReader()
-
-    def test_number_input(self):
-        x = self.graphson_reader.readObject(json.dumps({
-            "@type": "gx:Byte",
-            "@value": 1
-        }))
-        assert isinstance(x, SingleByte)
-        assert 1 == x
-        x = self.graphson_reader.readObject(json.dumps({
-            "@type": "g:Int32",
-            "@value": 31
-        }))
-        assert isinstance(x, int)
-        assert 31 == x
-        ##
-        x = self.graphson_reader.readObject(json.dumps({
-            "@type": "g:Int64",
-            "@value": 31
-        }))
-        assert isinstance(x, long)
-        assert long(31) == x
-        ##
-        x = self.graphson_reader.readObject(json.dumps({
-            "@type": "g:Float",
-            "@value": 31.3
-        }))
-        assert isinstance(x, float)
-        assert 31.3 == x
-        ##
-        x = self.graphson_reader.readObject(json.dumps({
-            "@type": "g:Double",
-            "@value": 31.2
-        }))
-        assert isinstance(x, float)
-        assert 31.2 == x
-        ##
-        x = self.graphson_reader.readObject(json.dumps({
-            "@type": "g:Double",
-            "@value": "NaN"
-        }))
-        assert isinstance(x, float)
-        assert math.isnan(x)
-        ##
-        x = self.graphson_reader.readObject(json.dumps({
-            "@type": "g:Double",
-            "@value": "Infinity"
-        }))
-        assert isinstance(x, float)
-        assert math.isinf(x) and x > 0
-        ##
-        x = self.graphson_reader.readObject(json.dumps({
-            "@type": "g:Double",
-            "@value": "-Infinity"
-        }))
-        assert isinstance(x, float)
-        assert math.isinf(x) and x < 0
-        ##
-        x = self.graphson_reader.readObject(json.dumps({
-            "@type": "gx:BigDecimal",
-            "@value": 31.2
-        }))
-        assert isinstance(x, Decimal)
-        assert Decimal(31.2) == x
-        ##
-        x = self.graphson_reader.readObject(json.dumps({
-            "@type": "gx:BigDecimal",
-            "@value": 123456789987654321123456789987654321
-        }))
-        assert isinstance(x, Decimal)
-        assert Decimal('123456789987654321123456789987654321') == x
-        ##
-        x = self.graphson_reader.readObject(json.dumps({
-            "@type": "gx:BigDecimal",
-            "@value": "NaN"
-        }))
-        assert isinstance(x, Decimal)
-        assert math.isnan(x)
-        ##
-        x = self.graphson_reader.readObject(json.dumps({
-            "@type": "gx:BigDecimal",
-            "@value": "Infinity"
-        }))
-        assert isinstance(x, Decimal)
-        assert math.isinf(x) and x > 0
-        ##
-        x = self.graphson_reader.readObject(json.dumps({
-            "@type": "gx:BigDecimal",
-            "@value": "-Infinity"
-        }))
-        assert isinstance(x, Decimal)
-        assert math.isinf(x) and x < 0
-        ##
-        x = self.graphson_reader.readObject(json.dumps({
-            "@type": "gx:BigInteger",
-            "@value": 31
-        }))
-        assert isinstance(x, long)
-        assert 31 == x
-        ##
-        x = self.graphson_reader.readObject(json.dumps({
-            "@type": "gx:BigInteger",
-            "@value": 123456789987654321123456789987654321
-        }))
-        assert isinstance(x, long)
-        assert 123456789987654321123456789987654321 == x
-
-    def test_graph(self):
-        vertex = self.graphson_reader.readObject("""
-        {"@type":"g:Vertex", "@value":{"id":{"@type":"g:Int32","@value":1},"label":"person","outE":{"created":[{"id":{"@type":"g:Int32","@value":9},"inV":{"@type":"g:Int32","@value":3},"properties":{"weight":{"@type":"g:Double","@value":0.4}}}],"knows":[{"id":{"@type":"g:Int32","@value":7},"inV":{"@type":"g:Int32","@value":2},"properties":{"weight":{"@type":"g:Double","@value":0.5}}},{"id":{"@type":"g:Int32","@value":8},"inV":{"@type":"g:Int32","@value":4},"properties":{"weight":{"@type":"g:Double","@value":1.0}}}]},"properties":{"name":[{"id":{"@type":"g:Int64","@value":0},"value":"marko"}],"age":[{"id":{"@type":"g:Int64","@value":1},"value":{"@type":"g:Int32","@value":29}}]}}}""")
-        assert isinstance(vertex, Vertex)
-        assert "person" == vertex.label
-        assert 1 == vertex.id
-        assert isinstance(vertex.id, int)
-        assert vertex == Vertex(1)
-        ##
-        vertex = self.graphson_reader.readObject("""
-        {"@type":"g:Vertex", "@value":{"id":{"@type":"g:Float","@value":45.23}}}""")
-        assert isinstance(vertex, Vertex)
-        assert 45.23 == vertex.id
-        assert isinstance(vertex.id, FloatType)
-        assert "vertex" == vertex.label
-        assert vertex == Vertex(45.23)
-        ##
-        vertex_property = self.graphson_reader.readObject("""
-        {"@type":"g:VertexProperty", "@value":{"id":"anId","label":"aKey","value":true,"vertex":{"@type":"g:Int32","@value":9}}}""")
-        assert isinstance(vertex_property, VertexProperty)
-        assert "anId" == vertex_property.id
-        assert "aKey" == vertex_property.label
-        assert vertex_property.value
-        assert vertex_property.vertex == Vertex(9)
-        ##
-        vertex_property = self.graphson_reader.readObject("""
-        {"@type":"g:VertexProperty", "@value":{"id":{"@type":"g:Int32","@value":1},"label":"name","value":"marko"}}""")
-        assert isinstance(vertex_property, VertexProperty)
-        assert 1 == vertex_property.id
-        assert "name" == vertex_property.label
-        assert "marko" == vertex_property.value
-        assert vertex_property.vertex is None
-        ##
-        edge = self.graphson_reader.readObject("""
-        {"@type":"g:Edge", "@value":{"id":{"@type":"g:Int64","@value":17},"label":"knows","inV":"x","outV":"y","inVLabel":"xLab","properties":{"aKey":"aValue","bKey":true}}}""")
-        # print edge
-        assert isinstance(edge, Edge)
-        assert 17 == edge.id
-        assert "knows" == edge.label
-        assert edge.inV == Vertex("x", "xLabel")
-        assert edge.outV == Vertex("y", "vertex")
-        ##
-        property = self.graphson_reader.readObject("""
-        {"@type":"g:Property", "@value":{"key":"aKey","value":{"@type":"g:Int64","@value":17},"element":{"@type":"g:Edge","@value":{"id":{"@type":"g:Int64","@value":122},"label":"knows","inV":"x","outV":"y","inVLabel":"xLab"}}}}""")
-        # print property
-        assert isinstance(property, Property)
-        assert "aKey" == property.key
-        assert 17 == property.value
-        assert Edge(122, Vertex("x"), "knows", Vertex("y")) == property.element
-
-    def test_path(self):
-        path = self.graphson_reader.readObject(
-            """{"@type":"g:Path","@value":{"labels":[["a"],["b","c"],[]],"objects":[{"@type":"g:Vertex","@value":{"id":{"@type":"g:Int32","@value":1},"label":"person","properties":{"name":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":0},"value":"marko","label":"name"}}],"age":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":1},"value":{"@type":"g:Int32","@value":29},"label":"age"}}]}}},{"@type":"g:Vertex","@value":{"id":{"@type":"g:Int32","@value":3},"label":"software","properties":{"name":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":4},"value":"lop","label":"name"}}],"lang":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":5},"value":"java","label":"lang"}}]}}},"lop"]}}"""
-        )
-        assert isinstance(path, Path)
-        assert "path[v[1], v[3], lop]" == str(path)
-        assert Vertex(1) == path[0]
-        assert Vertex(1) == path["a"]
-        assert "lop" == path[2]
-        assert 3 == len(path)
-
-    def test_custom_mapping(self):
-
-        # extended mapping
-        class X(object):
-            pass
-
-        type_string = "test:Xtype"
-        override_string = "g:Int64"
-        serdes = Mock()
-
-        reader = GraphSONReader(deserializer_map={type_string: serdes})
-        assert type_string in reader.deserializers
-
-        # base dicts are not modified
-        assert type_string not in gremlin_python.structure.io.graphsonV2d0._deserializers
-
-        x = X()
-        o = reader.toObject({GraphSONUtil.TYPE_KEY: type_string, GraphSONUtil.VALUE_KEY: x})
-        serdes.objectify.assert_called_once_with(x, reader)
-        assert o is serdes.objectify()
-
-        # overridden mapping
-        type_string = "g:Int64"
-        serdes = Mock()
-        reader = GraphSONReader(deserializer_map={type_string: serdes, override_string: serdes})
-        assert gremlin_python.structure.io.graphsonV2d0._deserializers[type_string] is not reader.deserializers[type_string]
-
-        value = 3
-        o = reader.toObject({GraphSONUtil.TYPE_KEY: type_string, GraphSONUtil.VALUE_KEY: value})
-        serdes.objectify.assert_called_once_with(value, reader)
-        assert o is serdes.objectify()
-
-    def test_datetime(self):
-        expected = datetime.datetime(2016, 12, 14, 16, 14, 36, 295000)
-        pts = calendar.timegm(expected.utctimetuple()) + expected.microsecond / 1e6
-        ts = int(round(pts * 1000))
-        dt = self.graphson_reader.readObject(json.dumps({"@type": "g:Date", "@value": ts}))
-        assert isinstance(dt, datetime.datetime)
-        # TINKERPOP-1848
-        assert dt == expected
-
-    def test_timestamp(self):
-        dt = self.graphson_reader.readObject(json.dumps({"@type": "g:Timestamp", "@value": 1481750076295}))
-        assert isinstance(dt, timestamp)
-        assert float(dt) == 1481750076.295
-
-    def test_duration(self):
-        d = self.graphson_reader.readObject(json.dumps({"@type": "gx:Duration", "@value": "PT120H"}))
-        assert isinstance(d, datetime.timedelta)
-        assert d == datetime.timedelta(hours=120)
-
-    def test_uuid(self):
-        prop = self.graphson_reader.readObject(
-            json.dumps({'@type': 'g:UUID', '@value': "41d2e28a-20a4-4ab0-b379-d810dede3786"}))
-        assert isinstance(prop, uuid.UUID)
-        assert str(prop) == '41d2e28a-20a4-4ab0-b379-d810dede3786'
-
-    def test_metrics(self):
-        prop = self.graphson_reader.readObject(
-            json.dumps([{'@type': 'g:TraversalMetrics', '@value': {'dur': 1.468594, 'metrics': [
-                {'@type': 'g:Metrics', '@value': {'dur': 1.380957, 'counts': {}, 'name': 'GraphStep(__.V())', 'annotations': {'percentDur': 94.03259171697556}, 'id': '4.0.0()'}},
-                {'@type': 'g:Metrics', '@value': {'dur': 0.087637, 'counts': {}, 'name': 'ReferenceElementStep', 'annotations': {'percentDur': 5.967408283024444}, 'id': '3.0.0()'}}
-            ]}}]))
-        assert isinstance(prop, list)
-        assert prop == [{'dur': 1.468594, 'metrics': [
-                {'dur': 1.380957, 'counts': {}, 'name': 'GraphStep(__.V())', 'annotations': {'percentDur': 94.03259171697556}, 'id': '4.0.0()'},
-                {'dur': 0.087637, 'counts': {}, 'name': 'ReferenceElementStep', 'annotations': {'percentDur': 5.967408283024444}, 'id': '3.0.0()'}
-                ]}]
-
-    def test_bytebuffer(self):
-        bb = self.graphson_reader.readObject(
-            json.dumps({"@type": "gx:ByteBuffer", "@value": "c29tZSBieXRlcyBmb3IgeW91"}))
-        assert isinstance(bb, ByteBufferType)
-        assert ByteBufferType("c29tZSBieXRlcyBmb3IgeW91", "utf8") == bb
-
-    def test_char(self):
-        c = self.graphson_reader.readObject(json.dumps({"@type": "gx:Char", "@value": "L"}))
-        assert isinstance(c, SingleChar)
-        assert chr(76) == c
-
-
-class TestGraphSONWriter(object):
-    graphson_writer = GraphSONWriter()
-    graphson_reader = GraphSONReader()
-
-    def test_numbers(self):
-        assert {"@type": "gx:Byte", "@value": 1} == json.loads(self.graphson_writer.writeObject(int.__new__(SingleByte, 1)))
-        assert {"@type": "g:Int64", "@value": 2} == json.loads(self.graphson_writer.writeObject(long(2)))
-        assert {"@type": "g:Int64", "@value": 851401972585122} == json.loads(self.graphson_writer.writeObject(long(851401972585122)))
-        assert {"@type": "g:Int64", "@value": -2} == json.loads(self.graphson_writer.writeObject(long(-2)))
-        assert {"@type": "g:Int64", "@value": -851401972585122} == json.loads(self.graphson_writer.writeObject(long(-851401972585122)))
-        assert {"@type": "g:Int32", "@value": 1} == json.loads(self.graphson_writer.writeObject(1))
-        assert {"@type": "g:Int32", "@value": -1} == json.loads(self.graphson_writer.writeObject(-1))
-        assert {"@type": "g:Int64", "@value": 851401972585122} == json.loads(self.graphson_writer.writeObject(851401972585122))
-        assert {"@type": "g:Double", "@value": 3.2} == json.loads(self.graphson_writer.writeObject(3.2))
-        assert {"@type": "g:Double", "@value": "NaN"} == json.loads(self.graphson_writer.writeObject(float('nan')))
-        assert {"@type": "g:Double", "@value": "Infinity"} == json.loads(self.graphson_writer.writeObject(float('inf')))
-        assert {"@type": "g:Double", "@value": "-Infinity"} == json.loads(self.graphson_writer.writeObject(float('-inf')))
-        assert {"@type": "gx:BigDecimal", "@value": "123456789987654321123456789987654321"} == json.loads(self.graphson_writer.writeObject(Decimal('123456789987654321123456789987654321')))
-        assert {"@type": "gx:BigDecimal", "@value": "NaN"} == json.loads(self.graphson_writer.writeObject(Decimal('nan')))
-        assert {"@type": "gx:BigDecimal", "@value": "Infinity"} == json.loads(self.graphson_writer.writeObject(Decimal('inf')))
-        assert {"@type": "gx:BigDecimal", "@value": "-Infinity"} == json.loads(self.graphson_writer.writeObject(Decimal('-inf')))
-        assert {"@type": "gx:BigInteger", "@value": "123456789987654321123456789987654321"} == json.loads(self.graphson_writer.writeObject(long(123456789987654321123456789987654321)))
-        assert {"@type": "gx:BigInteger", "@value": "123456789987654321123456789987654321"} == json.loads(self.graphson_writer.writeObject(123456789987654321123456789987654321))
-        assert """true""" == self.graphson_writer.writeObject(True)
-
-    def test_P(self):
-        result = {'@type': 'g:P',
-                  '@value': {
-                      'predicate': 'and',
-                      'value': [{
-                          '@type': 'g:P',
-                          '@value': {
-                              'predicate': 'or',
-                              'value': [{
-                                  '@type': 'g:P',
-                                  '@value': {'predicate': 'lt', 'value': 'b'}
-                              },
-                                  {'@type': 'g:P', '@value': {'predicate': 'gt', 'value': 'c'}}
-                              ]
-                          }
-                      },
-                          {'@type': 'g:P', '@value': {'predicate': 'neq', 'value': 'd'}}]}}
-
-        assert result == json.loads(
-            self.graphson_writer.writeObject(P.lt("b").or_(P.gt("c")).and_(P.neq("d"))))
-
-        result = {'@type': 'g:P', '@value': {'predicate':'within','value': [{"@type": "g:Int32", "@value": 1},{"@type": "g:Int32", "@value": 2}]}}
-        assert result == json.loads(self.graphson_writer.writeObject(P.within([1, 2])))
-        assert result == json.loads(self.graphson_writer.writeObject(P.within(1, 2)))
-
-        result = {'@type': 'g:P', '@value': {'predicate':'within','value': [{"@type": "g:Int32", "@value": 1}]}}
-        assert result == json.loads(self.graphson_writer.writeObject(P.within([1])))
-        assert result == json.loads(self.graphson_writer.writeObject(P.within(1)))
-
-    def test_strategies(self):
-        # we have a proxy model for now given that we don't want to have to have g:XXX all registered on the Gremlin traversal machine (yet)
-        assert {"@type": "g:SubgraphStrategy", "@value": {}} == json.loads(
-            self.graphson_writer.writeObject(SubgraphStrategy))
-        assert {"@type": "g:SubgraphStrategy", "@value": {
-            "vertices": {"@type": "g:Bytecode", "@value": {"step": [["has", "name", "marko"]]}}}} == json.loads(
-            self.graphson_writer.writeObject(SubgraphStrategy(vertices=__.has("name", "marko"))))
-
-    def test_graph(self):
-        # TODO: this assert is not compatible with python 3 and now that we test with both 2 and 3 it fails
-        assert {"@type": "g:Vertex", "@value": {"id": {"@type": "g:Int64", "@value": 12}, "label": "person"}} == json.loads(self.graphson_writer.writeObject(Vertex(long(12), "person")))
-
-        assert {"@type": "g:Edge", "@value": {"id": {"@type": "g:Int32", "@value": 7},
-                                              "outV": {"@type": "g:Int32", "@value": 0},
-                                              "outVLabel": "person",
-                                              "label": "knows",
-                                              "inV": {"@type": "g:Int32", "@value": 1},
-                                              "inVLabel": "dog"}} == json.loads(
-            self.graphson_writer.writeObject(Edge(7, Vertex(0, "person"), "knows", Vertex(1, "dog"))))
-        assert {"@type": "g:VertexProperty", "@value": {"id": "blah", "label": "keyA", "value": True,
-                                                        "vertex": "stephen"}} == json.loads(
-            self.graphson_writer.writeObject(VertexProperty("blah", "keyA", True, Vertex("stephen"))))
-
-        assert {"@type": "g:Property",
-                "@value": {"key": "name", "value": "marko", "element": {"@type": "g:VertexProperty",
-                                                                        "@value": {
-                                                                            "vertex": "vertexId",
-                                                                            "id": {"@type": "g:Int32", "@value": 1234},
-                                                                            "label": "aKey"}}}} == json.loads(
-            self.graphson_writer.writeObject(
-                Property("name", "marko", VertexProperty(1234, "aKey", 21345, Vertex("vertexId")))))
-
-        vertex = self.graphson_reader.readObject(self.graphson_writer.writeObject(Vertex(1, "person")))
-        assert 1 == vertex.id
-        assert "person" == vertex.label
-
-        edge = self.graphson_reader.readObject(
-            self.graphson_writer.writeObject(Edge(3, Vertex(1, "person"), "knows", Vertex(2, "dog"))))
-        assert "knows" == edge.label
-        assert 3 == edge.id
-        assert 1 == edge.outV.id
-        assert 2 == edge.inV.id
-
-        vertex_property = self.graphson_reader.readObject(
-            self.graphson_writer.writeObject(VertexProperty(1, "age", 32, Vertex(1))))
-        assert 1 == vertex_property.id
-        assert "age" == vertex_property.key
-        assert 32 == vertex_property.value
-
-        property = self.graphson_reader.readObject(self.graphson_writer.writeObject(Property("age", 32.2, Edge(1,Vertex(2),"knows",Vertex(3)))))
-        assert "age" == property.key
-        assert 32.2 == property.value
-
-    def test_custom_mapping(self):
-        # extended mapping
-        class X(object):
-            pass
-
-        serdes = Mock()
-        writer = GraphSONWriter(serializer_map={X: serdes})
-        assert X in writer.serializers
-
-        # base dicts are not modified
-        assert X not in gremlin_python.structure.io.graphsonV2d0._serializers
-
-        obj = X()
-        d = writer.toDict(obj)
-        serdes.dictify.assert_called_once_with(obj, writer)
-        assert d is serdes.dictify()
-
-        # overridden mapping
-        serdes = Mock()
-        writer = GraphSONWriter(serializer_map={int: serdes})
-        assert gremlin_python.structure.io.graphsonV2d0._serializers[int] is not writer.serializers[int]
-
-        value = 3
-        d = writer.toDict(value)
-        serdes.dictify.assert_called_once_with(value, writer)
-        assert d is serdes.dictify()
-
-    def test_write_long(self):
-        mapping = self.graphson_writer.toDict(1)
-        assert mapping['@type'] == 'g:Int32'
-        assert mapping['@value'] == 1
-
-        mapping = self.graphson_writer.toDict(long(1))
-        assert mapping['@type'] == 'g:Int64'
-        assert mapping['@value'] == 1
-
-    def test_datetime(self):
-        expected = json.dumps({"@type": "g:Date", "@value": 1481750076295}, separators=(',', ':'))
-        dt = datetime.datetime.utcfromtimestamp(1481750076295 / 1000.0)
-        output = self.graphson_writer.writeObject(dt)
-        assert expected == output
-
-    def test_timestamp(self):
-        expected = json.dumps({"@type": "g:Timestamp", "@value": 1481750076295}, separators=(',', ':'))
-        ts = timestamp(1481750076295 / 1000.0)
-        output = self.graphson_writer.writeObject(ts)
-        assert expected == output
-
-    def test_duration(self):
-        expected = json.dumps({"@type": "gx:Duration", "@value": "P5D"}, separators=(',', ':'))
-        d = datetime.timedelta(hours=120)
-        output = self.graphson_writer.writeObject(d)
-        assert expected == output
-
-    def test_uuid(self):
-        expected = json.dumps({'@type': 'g:UUID', '@value': "41d2e28a-20a4-4ab0-b379-d810dede3786"}, separators=(',', ':'))
-        prop = uuid.UUID("41d2e28a-20a4-4ab0-b379-d810dede3786")
-        output = self.graphson_writer.writeObject(prop)
-        assert expected == output
-
-    def test_bytebuffer(self):
-        expected = json.dumps({'@type': 'gx:ByteBuffer', '@value': 'c29tZSBieXRlcyBmb3IgeW91'}, separators=(',', ':'))
-        bb = ByteBufferType("c29tZSBieXRlcyBmb3IgeW91", "utf8")
-        output = self.graphson_writer.writeObject(bb)
-        assert expected == output
-
-    def test_char(self):
-        expected = json.dumps({'@type': 'gx:Char', '@value': 'L'}, separators=(',', ':'))
-        c = str.__new__(SingleChar, chr(76))
-        output = self.graphson_writer.writeObject(c)
-        assert expected == output
-
-
-class TestFunctionalGraphSONIO(object):
-    """Functional IO tests"""
-
-    def test_timestamp(self, remote_connection_v2):
-        g = Graph().traversal().withRemote(remote_connection_v2)
-        ts = timestamp(1481750076295 / 1000)
-        resp = g.addV('test_vertex').property('ts', ts)
-        resp = resp.toList()
-        vid = resp[0].id
-        try:
-            ts_prop = g.V(vid).properties('ts').toList()[0]
-            assert isinstance(ts_prop.value, timestamp)
-            assert ts_prop.value == ts
-        except OSError:
-            assert False, "Error making request"
-        finally:
-            g.V(vid).drop().iterate()
-
-    def test_datetime(self, remote_connection_v2):
-        g = Graph().traversal().withRemote(remote_connection_v2)
-        dt = datetime.datetime.utcfromtimestamp(1481750076295 / 1000)
-        resp = g.addV('test_vertex').property('dt', dt).toList()
-        vid = resp[0].id
-        try:
-            dt_prop = g.V(vid).properties('dt').toList()[0]
-            assert isinstance(dt_prop.value, datetime.datetime)
-            assert dt_prop.value == dt
-        except OSError:
-            assert False, "Error making request"
-        finally:
-            g.V(vid).drop().iterate()
-
-    def test_uuid(self, remote_connection_v2):
-        g = Graph().traversal().withRemote(remote_connection_v2)
-        uid = uuid.UUID("41d2e28a-20a4-4ab0-b379-d810dede3786")
-        resp = g.addV('test_vertex').property('uuid', uid).toList()
-        vid = resp[0].id
-        try:
-            uid_prop = g.V(vid).properties('uuid').toList()[0]
-            assert isinstance(uid_prop.value, uuid.UUID)
-            assert uid_prop.value == uid
-        except OSError:
-            assert False, "Error making request"
-        finally:
-            g.V(vid).drop().iterate()
diff --git a/gremlin-python/src/main/jython/tests/structure/io/test_graphsonV3d0.py b/gremlin-python/src/main/jython/tests/structure/io/test_graphsonV3d0.py
deleted file mode 100644
index f3948fd..0000000
--- a/gremlin-python/src/main/jython/tests/structure/io/test_graphsonV3d0.py
+++ /dev/null
@@ -1,534 +0,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.
-#
-
-__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
-
-import datetime
-import calendar
-import json
-import uuid
-import math
-from decimal import *
-
-from mock import Mock
-
-import six
-
-from gremlin_python.statics import *
-from gremlin_python.structure.graph import Vertex, Edge, Property, VertexProperty, Graph, Path
-from gremlin_python.structure.io.graphsonV3d0 import GraphSONWriter, GraphSONReader, GraphSONUtil
-import gremlin_python.structure.io.graphsonV3d0
-from gremlin_python.process.traversal import P
-from gremlin_python.process.strategies import SubgraphStrategy
-from gremlin_python.process.graph_traversal import __
-
-
-class TestGraphSONReader(object):
-    graphson_reader = GraphSONReader()
-
-    def test_collections(self):
-        x = self.graphson_reader.readObject(
-            json.dumps({"@type": "g:List", "@value": [{"@type": "g:Int32", "@value": 1},
-                                                      {"@type": "g:Int32", "@value": 2},
-                                                      "3"]}))
-        assert isinstance(x, list)
-        assert x[0] == 1
-        assert x[1] == 2
-        assert x[2] == "3"
-        ##
-
-        x = self.graphson_reader.readObject(
-            json.dumps({"@type": "g:Set", "@value": [{"@type": "g:Int32", "@value": 1},
-                                                     {"@type": "g:Int32", "@value": 2},
-                                                     "3"]}))
-        # return a set as normal
-        assert isinstance(x, set)
-        assert x == set([1, 2, "3"])
-
-        x = self.graphson_reader.readObject(
-            json.dumps({"@type": "g:Set", "@value": [{"@type": "g:Int32", "@value": 1},
-                                                    {"@type": "g:Int32", "@value": 2},
-                                                    {"@type": "g:Float", "@value": 2.0},
-                                                    "3"]}))
-        # coerce to list here because Java might return numerics of different types which python won't recognize
-        # see comments of TINKERPOP-1844 for more details
-        assert isinstance(x, list)
-        assert x == list([1, 2, 2.0, "3"])
-        ##
-        x = self.graphson_reader.readObject(
-            json.dumps({"@type": "g:Map",
-                        "@value": ['a', {"@type": "g:Int32", "@value": 1}, 'b', "marko"]}))
-        assert isinstance(x, dict)
-        assert x['a'] == 1
-        assert x['b'] == "marko"
-        assert len(x) == 2
-
-        # BulkSet gets coerced to a List - both have the same behavior
-        x = self.graphson_reader.readObject(
-            json.dumps({"@type": "g:BulkSet",
-                        "@value": ["marko", {"@type": "g:Int64", "@value": 1}, "josh", {"@type": "g:Int64", "@value": 3}]}))
-        assert isinstance(x, list)
-        assert len(x) == 4
-        assert x.count("marko") == 1
-        assert x.count("josh") == 3
-
-    def test_number_input(self):
-        x = self.graphson_reader.readObject(json.dumps({
-            "@type": "gx:Byte",
-            "@value": 1
-        }))
-        assert isinstance(x, SingleByte)
-        assert 1 == x
-        x = self.graphson_reader.readObject(json.dumps({
-            "@type": "g:Int32",
-            "@value": 31
-        }))
-        assert isinstance(x, int)
-        assert 31 == x
-        ##
-        x = self.graphson_reader.readObject(json.dumps({
-            "@type": "g:Int64",
-            "@value": 31
-        }))
-        assert isinstance(x, long)
-        assert long(31) == x
-        ##
-        x = self.graphson_reader.readObject(json.dumps({
-            "@type": "g:Float",
-            "@value": 31.3
-        }))
-        assert isinstance(x, float)
-        assert 31.3 == x
-        ##
-        x = self.graphson_reader.readObject(json.dumps({
-            "@type": "g:Double",
-            "@value": 31.2
-        }))
-        assert isinstance(x, float)
-        assert 31.2 == x
-        ##
-        x = self.graphson_reader.readObject(json.dumps({
-            "@type": "g:Double",
-            "@value": "NaN"
-        }))
-        assert isinstance(x, float)
-        assert math.isnan(x)
-        ##
-        x = self.graphson_reader.readObject(json.dumps({
-            "@type": "g:Double",
-            "@value": "Infinity"
-        }))
-        assert isinstance(x, float)
-        assert math.isinf(x) and x > 0
-        ##
-        x = self.graphson_reader.readObject(json.dumps({
-            "@type": "g:Double",
-            "@value": "-Infinity"
-        }))
-        assert isinstance(x, float)
-        assert math.isinf(x) and x < 0
-        ##
-        x = self.graphson_reader.readObject(json.dumps({
-            "@type": "gx:BigDecimal",
-            "@value": 31.2
-        }))
-        assert isinstance(x, Decimal)
-        assert Decimal(31.2) == x
-        ##
-        x = self.graphson_reader.readObject(json.dumps({
-            "@type": "gx:BigDecimal",
-            "@value": 123456789987654321123456789987654321
-        }))
-        assert isinstance(x, Decimal)
-        assert Decimal('123456789987654321123456789987654321') == x
-        ##
-        x = self.graphson_reader.readObject(json.dumps({
-            "@type": "gx:BigDecimal",
-            "@value": "NaN"
-        }))
-        assert isinstance(x, Decimal)
-        assert math.isnan(x)
-        ##
-        x = self.graphson_reader.readObject(json.dumps({
-            "@type": "gx:BigDecimal",
-            "@value": "Infinity"
-        }))
-        assert isinstance(x, Decimal)
-        assert math.isinf(x) and x > 0
-        ##
-        x = self.graphson_reader.readObject(json.dumps({
-            "@type": "gx:BigDecimal",
-            "@value": "-Infinity"
-        }))
-        assert isinstance(x, Decimal)
-        assert math.isinf(x) and x < 0
-        ##
-        x = self.graphson_reader.readObject(json.dumps({
-            "@type": "gx:BigInteger",
-            "@value": 31
-        }))
-        assert isinstance(x, long)
-        assert 31 == x
-        ##
-        x = self.graphson_reader.readObject(json.dumps({
-            "@type": "gx:BigInteger",
-            "@value": 123456789987654321123456789987654321
-        }))
-        assert isinstance(x, long)
-        assert 123456789987654321123456789987654321 == x
-
-    def test_graph(self):
-        vertex = self.graphson_reader.readObject("""
-        {"@type":"g:Vertex", "@value":{"id":{"@type":"g:Int32","@value":1},"label":"person","outE":{"created":[{"id":{"@type":"g:Int32","@value":9},"inV":{"@type":"g:Int32","@value":3},"properties":{"weight":{"@type":"g:Double","@value":0.4}}}],"knows":[{"id":{"@type":"g:Int32","@value":7},"inV":{"@type":"g:Int32","@value":2},"properties":{"weight":{"@type":"g:Double","@value":0.5}}},{"id":{"@type":"g:Int32","@value":8},"inV":{"@type":"g:Int32","@value":4},"properties":{"weight":{"@type":"g:Double","@value":1.0}}}]},"properties":{"name":[{"id":{"@type":"g:Int64","@value":0},"value":"marko"}],"age":[{"id":{"@type":"g:Int64","@value":1},"value":{"@type":"g:Int32","@value":29}}]}}}""")
-        assert isinstance(vertex, Vertex)
-        assert "person" == vertex.label
-        assert 1 == vertex.id
-        assert isinstance(vertex.id, int)
-        assert vertex == Vertex(1)
-        ##
-        vertex = self.graphson_reader.readObject("""
-        {"@type":"g:Vertex", "@value":{"id":{"@type":"g:Float","@value":45.23}}}""")
-        assert isinstance(vertex, Vertex)
-        assert 45.23 == vertex.id
-        assert isinstance(vertex.id, FloatType)
-        assert "vertex" == vertex.label
-        assert vertex == Vertex(45.23)
-        ##
-        vertex_property = self.graphson_reader.readObject("""
-        {"@type":"g:VertexProperty", "@value":{"id":"anId","label":"aKey","value":true,"vertex":{"@type":"g:Int32","@value":9}}}""")
-        assert isinstance(vertex_property, VertexProperty)
-        assert "anId" == vertex_property.id
-        assert "aKey" == vertex_property.label
-        assert vertex_property.value
-        assert vertex_property.vertex == Vertex(9)
-        ##
-        vertex_property = self.graphson_reader.readObject("""
-        {"@type":"g:VertexProperty", "@value":{"id":{"@type":"g:Int32","@value":1},"label":"name","value":"marko"}}""")
-        assert isinstance(vertex_property, VertexProperty)
-        assert 1 == vertex_property.id
-        assert "name" == vertex_property.label
-        assert "marko" == vertex_property.value
-        assert vertex_property.vertex is None
-        ##
-        edge = self.graphson_reader.readObject("""
-        {"@type":"g:Edge", "@value":{"id":{"@type":"g:Int64","@value":17},"label":"knows","inV":"x","outV":"y","inVLabel":"xLab","properties":{"aKey":"aValue","bKey":true}}}""")
-        # print edge
-        assert isinstance(edge, Edge)
-        assert 17 == edge.id
-        assert "knows" == edge.label
-        assert edge.inV == Vertex("x", "xLabel")
-        assert edge.outV == Vertex("y", "vertex")
-        ##
-        property = self.graphson_reader.readObject("""
-        {"@type":"g:Property", "@value":{"key":"aKey","value":{"@type":"g:Int64","@value":17},"element":{"@type":"g:Edge","@value":{"id":{"@type":"g:Int64","@value":122},"label":"knows","inV":"x","outV":"y","inVLabel":"xLab"}}}}""")
-        # print property
-        assert isinstance(property, Property)
-        assert "aKey" == property.key
-        assert 17 == property.value
-        assert Edge(122, Vertex("x"), "knows", Vertex("y")) == property.element
-
-    def test_path(self):
-        path = self.graphson_reader.readObject(
-            """{"@type":"g:Path","@value":{"labels":{"@type":"g:List","@value":[{"@type":"g:Set","@value":["a"]},{"@type":"g:Set","@value":["b","c"]},{"@type":"g:Set","@value":[]}]},"objects":{"@type":"g:List","@value":[{"@type":"g:Vertex","@value":{"id":{"@type":"g:Int32","@value":1},"label":"person","properties":{"name":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":0},"value":"marko","label":"name"}}],"age":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":1},"value":{"@type":"g:Int32","@value":29},"label":"age"}}]}}},{"@type":"g:Vertex","@value":{"id":{"@type":"g:Int32","@value":3},"label":"software","properties":{"name":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":4},"value":"lop","label":"name"}}],"lang":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":5},"value":"java","label":"lang"}}]}}},"lop"]}}}"""
-        )
-        assert isinstance(path, Path)
-        assert "path[v[1], v[3], lop]" == str(path)
-        assert Vertex(1) == path[0]
-        assert Vertex(1) == path["a"]
-        assert "lop" == path[2]
-        assert 3 == len(path)
-
-    def test_custom_mapping(self):
-
-        # extended mapping
-        class X(object):
-            pass
-
-        type_string = "test:Xtype"
-        override_string = "g:Int64"
-        serdes = Mock()
-
-        reader = GraphSONReader(deserializer_map={type_string: serdes})
-        assert type_string in reader.deserializers
-
-        # base dicts are not modified
-        assert type_string not in gremlin_python.structure.io.graphsonV3d0._deserializers
-
-        x = X()
-        o = reader.toObject({GraphSONUtil.TYPE_KEY: type_string, GraphSONUtil.VALUE_KEY: x})
-        serdes.objectify.assert_called_once_with(x, reader)
-        assert o is serdes.objectify()
-
-        # overridden mapping
-        type_string = "g:Int64"
-        serdes = Mock()
-        reader = GraphSONReader(deserializer_map={type_string: serdes, override_string: serdes})
-        assert gremlin_python.structure.io.graphsonV3d0._deserializers[type_string] is not reader.deserializers[
-            type_string]
-
-        value = 3
-        o = reader.toObject({GraphSONUtil.TYPE_KEY: type_string, GraphSONUtil.VALUE_KEY: value})
-        serdes.objectify.assert_called_once_with(value, reader)
-        assert o is serdes.objectify()
-
-    def test_datetime(self):
-        expected = datetime.datetime(2016, 12, 14, 16, 14, 36, 295000)
-        pts = calendar.timegm(expected.utctimetuple()) + expected.microsecond / 1e6
-        ts = int(round(pts * 1000))
-        dt = self.graphson_reader.readObject(json.dumps({"@type": "g:Date", "@value": ts}))
-        assert isinstance(dt, datetime.datetime)
-        # TINKERPOP-1848
-        assert dt == expected
-
-    def test_timestamp(self):
-        dt = self.graphson_reader.readObject(json.dumps({"@type": "g:Timestamp", "@value": 1481750076295}))
-        assert isinstance(dt, timestamp)
-        assert float(dt) == 1481750076.295
-
-    def test_duration(self):
-        d = self.graphson_reader.readObject(json.dumps({"@type": "gx:Duration", "@value": "PT120H"}))
-        assert isinstance(d, datetime.timedelta)
-        assert d == datetime.timedelta(hours=120)
-
-    def test_uuid(self):
-        prop = self.graphson_reader.readObject(
-            json.dumps({'@type': 'g:UUID', '@value': "41d2e28a-20a4-4ab0-b379-d810dede3786"}))
-        assert isinstance(prop, uuid.UUID)
-        assert str(prop) == '41d2e28a-20a4-4ab0-b379-d810dede3786'
-
-    def test_metrics(self):
-        prop = self.graphson_reader.readObject(
-            json.dumps([{'@type': 'g:TraversalMetrics', '@value': {'dur': 1.468594, 'metrics': [
-                {'@type': 'g:Metrics', '@value': {'dur': 1.380957, 'counts': {}, 'name': 'GraphStep(__.V())', 'annotations': {'percentDur': 94.03259171697556}, 'id': '4.0.0()'}},
-                {'@type': 'g:Metrics', '@value': {'dur': 0.087637, 'counts': {}, 'name': 'ReferenceElementStep', 'annotations': {'percentDur': 5.967408283024444}, 'id': '3.0.0()'}}
-            ]}}]))
-        assert isinstance(prop, list)
-        assert prop == [{'dur': 1.468594, 'metrics': [
-                {'dur': 1.380957, 'counts': {}, 'name': 'GraphStep(__.V())', 'annotations': {'percentDur': 94.03259171697556}, 'id': '4.0.0()'},
-                {'dur': 0.087637, 'counts': {}, 'name': 'ReferenceElementStep', 'annotations': {'percentDur': 5.967408283024444}, 'id': '3.0.0()'}
-                ]}]
-
-    def test_bytebuffer(self):
-        bb = self.graphson_reader.readObject(
-            json.dumps({"@type": "gx:ByteBuffer", "@value": "c29tZSBieXRlcyBmb3IgeW91"}))
-        assert isinstance(bb, ByteBufferType)
-        assert ByteBufferType("c29tZSBieXRlcyBmb3IgeW91", "utf8") == bb
-
-    def test_char(self):
-        c = self.graphson_reader.readObject(json.dumps({"@type": "gx:Char", "@value": "L"}))
-        assert isinstance(c, SingleChar)
-        assert chr(76) == c
-
-
-class TestGraphSONWriter(object):
-    graphson_writer = GraphSONWriter()
-    graphson_reader = GraphSONReader()
-
-    def test_collections(self):
-        assert {"@type": "g:List", "@value": [{"@type": "g:Int32", "@value": 1},
-                                              {"@type": "g:Int32", "@value": 2},
-                                              {"@type": "g:Int32", "@value": 3}]} == json.loads(
-            self.graphson_writer.writeObject([1, 2, 3]))
-        assert {"@type": "g:Set", "@value": [{"@type": "g:Int32", "@value": 1},
-                                             {"@type": "g:Int32", "@value": 2},
-                                             {"@type": "g:Int32", "@value": 3}]} == json.loads(
-            self.graphson_writer.writeObject(set([1, 2, 3, 3])))
-        assert {"@type": "g:Map",
-                "@value": ['a', {"@type": "g:Int32", "@value": 1}]} == json.loads(
-            self.graphson_writer.writeObject({'a': 1}))
-
-    def test_numbers(self):
-        assert {"@type": "gx:Byte", "@value": 1} == json.loads(self.graphson_writer.writeObject(int.__new__(SingleByte, 1)))
-        assert {"@type": "g:Int64", "@value": 2} == json.loads(self.graphson_writer.writeObject(long(2)))
-        assert {"@type": "g:Int64", "@value": 851401972585122} == json.loads(self.graphson_writer.writeObject(long(851401972585122)))
-        assert {"@type": "g:Int64", "@value": -2} == json.loads(self.graphson_writer.writeObject(long(-2)))
-        assert {"@type": "g:Int64", "@value": -851401972585122} == json.loads(self.graphson_writer.writeObject(long(-851401972585122)))
-        assert {"@type": "g:Int32", "@value": 1} == json.loads(self.graphson_writer.writeObject(1))
-        assert {"@type": "g:Int32", "@value": -1} == json.loads(self.graphson_writer.writeObject(-1))
-        assert {"@type": "g:Int64", "@value": 851401972585122} == json.loads(self.graphson_writer.writeObject(851401972585122))
-        assert {"@type": "g:Double", "@value": 3.2} == json.loads(self.graphson_writer.writeObject(3.2))
-        assert {"@type": "g:Double", "@value": "NaN"} == json.loads(self.graphson_writer.writeObject(float('nan')))
-        assert {"@type": "g:Double", "@value": "Infinity"} == json.loads(self.graphson_writer.writeObject(float('inf')))
-        assert {"@type": "g:Double", "@value": "-Infinity"} == json.loads(self.graphson_writer.writeObject(float('-inf')))
-        assert {"@type": "gx:BigDecimal", "@value": "123456789987654321123456789987654321"} == json.loads(self.graphson_writer.writeObject(Decimal('123456789987654321123456789987654321')))
-        assert {"@type": "gx:BigDecimal", "@value": "NaN"} == json.loads(self.graphson_writer.writeObject(Decimal('nan')))
-        assert {"@type": "gx:BigDecimal", "@value": "Infinity"} == json.loads(self.graphson_writer.writeObject(Decimal('inf')))
-        assert {"@type": "gx:BigDecimal", "@value": "-Infinity"} == json.loads(self.graphson_writer.writeObject(Decimal('-inf')))
-        assert {"@type": "gx:BigInteger", "@value": "123456789987654321123456789987654321"} == json.loads(self.graphson_writer.writeObject(long(123456789987654321123456789987654321)))
-        assert {"@type": "gx:BigInteger", "@value": "123456789987654321123456789987654321"} == json.loads(self.graphson_writer.writeObject(123456789987654321123456789987654321))
-        assert """true""" == self.graphson_writer.writeObject(True)
-
-    def test_P(self):
-        result = {'@type': 'g:P',
-                  '@value': {
-                      'predicate': 'and',
-                      'value': [{
-                          '@type': 'g:P',
-                          '@value': {
-                              'predicate': 'or',
-                              'value': [{
-                                  '@type': 'g:P',
-                                  '@value': {'predicate': 'lt', 'value': 'b'}
-                              },
-                                  {'@type': 'g:P', '@value': {'predicate': 'gt', 'value': 'c'}}
-                              ]
-                          }
-                      },
-                          {'@type': 'g:P', '@value': {'predicate': 'neq', 'value': 'd'}}]}}
-
-        assert result == json.loads(
-            self.graphson_writer.writeObject(P.lt("b").or_(P.gt("c")).and_(P.neq("d"))))
-
-        result = {'@type': 'g:P', '@value': {'predicate': 'within', 'value': {'@type': 'g:List', '@value': [
-            {"@type": "g:Int32", "@value": 1}, {"@type": "g:Int32", "@value": 2}]}}}
-        assert result == json.loads(self.graphson_writer.writeObject(P.within([1, 2])))
-        assert result == json.loads(self.graphson_writer.writeObject(P.within(1, 2)))
-
-        result = {'@type': 'g:P', '@value': {'predicate': 'within', 'value': {'@type': 'g:List', '@value': [
-            {"@type": "g:Int32", "@value": 1}]}}}
-        assert result == json.loads(self.graphson_writer.writeObject(P.within([1])))
-        assert result == json.loads(self.graphson_writer.writeObject(P.within(1)))
-
-    def test_strategies(self):
-        # we have a proxy model for now given that we don't want to have to have g:XXX all registered on the 
-        # Gremlin traversal machine (yet)
-        assert {"@type": "g:SubgraphStrategy", "@value": {}} == json.loads(
-            self.graphson_writer.writeObject(SubgraphStrategy))
-        assert {"@type": "g:SubgraphStrategy", "@value": {
-            "vertices": {"@type": "g:Bytecode", "@value": {"step": [["has", "name", "marko"]]}}}} == json.loads(
-            self.graphson_writer.writeObject(SubgraphStrategy(vertices=__.has("name", "marko"))))
-
-    def test_graph(self):
-        # TODO: this assert is not compatible with python 3 and now that we test with both 2 and 3 it fails
-        assert {"@type": "g:Vertex",
-                "@value": {"id": {"@type": "g:Int64", "@value": 12}, "label": "person"}} == json.loads(
-            self.graphson_writer.writeObject(Vertex(long(12), "person")))
-
-        assert {"@type": "g:Edge", "@value": {"id": {"@type": "g:Int32", "@value": 7},
-                                              "outV": {"@type": "g:Int32", "@value": 0},
-                                              "outVLabel": "person",
-                                              "label": "knows",
-                                              "inV": {"@type": "g:Int32", "@value": 1},
-                                              "inVLabel": "dog"}} == json.loads(
-            self.graphson_writer.writeObject(Edge(7, Vertex(0, "person"), "knows", Vertex(1, "dog"))))
-        assert {"@type": "g:VertexProperty", "@value": {"id": "blah", "label": "keyA", "value": True,
-                                                        "vertex": "stephen"}} == json.loads(
-            self.graphson_writer.writeObject(VertexProperty("blah", "keyA", True, Vertex("stephen"))))
-
-        assert {"@type": "g:Property",
-                "@value": {"key": "name", "value": "marko", "element": {"@type": "g:VertexProperty",
-                                                                        "@value": {
-                                                                            "vertex": "vertexId",
-                                                                            "id": {"@type": "g:Int32", "@value": 1234},
-                                                                            "label": "aKey"}}}} == json.loads(
-            self.graphson_writer.writeObject(
-                Property("name", "marko", VertexProperty(1234, "aKey", 21345, Vertex("vertexId")))))
-
-        vertex = self.graphson_reader.readObject(self.graphson_writer.writeObject(Vertex(1, "person")))
-        assert 1 == vertex.id
-        assert "person" == vertex.label
-
-        edge = self.graphson_reader.readObject(
-            self.graphson_writer.writeObject(Edge(3, Vertex(1, "person"), "knows", Vertex(2, "dog"))))
-        assert "knows" == edge.label
-        assert 3 == edge.id
-        assert 1 == edge.outV.id
-        assert 2 == edge.inV.id
-
-        vertex_property = self.graphson_reader.readObject(
-            self.graphson_writer.writeObject(VertexProperty(1, "age", 32, Vertex(1))))
-        assert 1 == vertex_property.id
-        assert "age" == vertex_property.key
-        assert 32 == vertex_property.value
-
-        property = self.graphson_reader.readObject(self.graphson_writer.writeObject(Property("age", 32.2, Edge(1,Vertex(2),"knows",Vertex(3)))))
-        assert "age" == property.key
-        assert 32.2 == property.value
-
-    def test_custom_mapping(self):
-        # extended mapping
-        class X(object):
-            pass
-
-        serdes = Mock()
-        writer = GraphSONWriter(serializer_map={X: serdes})
-        assert X in writer.serializers
-
-        # base dicts are not modified
-        assert X not in gremlin_python.structure.io.graphsonV3d0._serializers
-
-        obj = X()
-        d = writer.toDict(obj)
-        serdes.dictify.assert_called_once_with(obj, writer)
-        assert d is serdes.dictify()
-
-        # overridden mapping
-        serdes = Mock()
-        writer = GraphSONWriter(serializer_map={int: serdes})
-        assert gremlin_python.structure.io.graphsonV3d0._serializers[int] is not writer.serializers[int]
-
-        value = 3
-        d = writer.toDict(value)
-        serdes.dictify.assert_called_once_with(value, writer)
-        assert d is serdes.dictify()
-
-    def test_write_long(self):
-        mapping = self.graphson_writer.toDict(1)
-        assert mapping['@type'] == 'g:Int32'
-        assert mapping['@value'] == 1
-
-        mapping = self.graphson_writer.toDict(long(1))
-        assert mapping['@type'] == 'g:Int64'
-        assert mapping['@value'] == 1
-
-    def test_datetime(self):
-        expected = json.dumps({"@type": "g:Date", "@value": 1481750076295}, separators=(',', ':'))
-        dt = datetime.datetime.utcfromtimestamp(1481750076295 / 1000.0)
-        output = self.graphson_writer.writeObject(dt)
-        assert expected == output
-
-    def test_timestamp(self):
-        expected = json.dumps({"@type": "g:Timestamp", "@value": 1481750076295}, separators=(',', ':'))
-        ts = timestamp(1481750076295 / 1000.0)
-        output = self.graphson_writer.writeObject(ts)
-        assert expected == output
-
-    def test_duration(self):
-        expected = json.dumps({"@type": "gx:Duration", "@value": "P5D"}, separators=(',', ':'))
-        d = datetime.timedelta(hours=120)
-        output = self.graphson_writer.writeObject(d)
-        assert expected == output
-
-    def test_uuid(self):
-        expected = json.dumps({'@type': 'g:UUID', '@value': "41d2e28a-20a4-4ab0-b379-d810dede3786"}, separators=(',', ':'))
-        prop = uuid.UUID("41d2e28a-20a4-4ab0-b379-d810dede3786")
-        output = self.graphson_writer.writeObject(prop)
-        assert expected == output
-
-    def test_bytebuffer(self):
-        expected = json.dumps({'@type': 'gx:ByteBuffer', '@value': 'c29tZSBieXRlcyBmb3IgeW91'}, separators=(',', ':'))
-        bb = ByteBufferType("c29tZSBieXRlcyBmb3IgeW91", "utf8")
-        output = self.graphson_writer.writeObject(bb)
-        assert expected == output
-
-    def test_char(self):
-        expected = json.dumps({'@type': 'gx:Char', '@value': 'L'}, separators=(',', ':'))
-        c = str.__new__(SingleChar, chr(76))
-        output = self.graphson_writer.writeObject(c)
-        assert expected == output
diff --git a/gremlin-python/src/main/jython/tests/structure/test_graph.py b/gremlin-python/src/main/jython/tests/structure/test_graph.py
deleted file mode 100644
index 67849f6..0000000
--- a/gremlin-python/src/main/jython/tests/structure/test_graph.py
+++ /dev/null
@@ -1,115 +0,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.
-#
-
-__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
-
-import six
-
-from gremlin_python.statics import long
-from gremlin_python.structure.graph import Edge
-from gremlin_python.structure.graph import Property
-from gremlin_python.structure.graph import Vertex
-from gremlin_python.structure.graph import VertexProperty
-from gremlin_python.structure.graph import Path
-
-
-class TestGraph(object):
-    def test_graph_objects(self):
-        vertex = Vertex(1)
-        assert "v[1]" == str(vertex)
-        assert "vertex" == vertex.label
-        assert "person" == Vertex(1, "person").label
-        assert vertex == Vertex(1)
-        #
-        edge = Edge(2, Vertex(1), "said", Vertex("hello", "phrase"))
-        assert "e[2][1-said->hello]" == str(edge)
-        assert Vertex(1) == edge.outV
-        assert Vertex("hello") == edge.inV
-        assert "said" == edge.label
-        assert "phrase" == edge.inV.label
-        assert edge.inV != edge.outV
-        #
-        vertex_property = VertexProperty(long(24), "name", "marko", Vertex(1))
-        assert "vp[name->marko]" == str(vertex_property)
-        assert "name" == vertex_property.label
-        assert "name" == vertex_property.key
-        assert "marko" == vertex_property.value
-        assert long(24) == vertex_property.id
-        assert Vertex(1) == vertex_property.vertex
-        assert isinstance(vertex_property.id, long)
-        assert vertex_property == VertexProperty(long(24), "name", "marko", Vertex(1))
-        #
-        property = Property("age", 29, Vertex(1))
-        assert "p[age->29]" == str(property)
-        assert "age" == property.key
-        assert 29 == property.value
-        assert Vertex(1) == property.element
-        assert isinstance(property.value, int)
-        assert property == Property("age", 29, Vertex(1))
-        if not six.PY3:
-            assert property != Property("age", long(29), Vertex(1))
-        #
-        for i in [vertex, edge, vertex_property, property]:
-            for j in [vertex, edge, vertex_property, property]:
-                if type(i) != type(j):
-                    assert i != j
-                else:
-                    assert i == j
-                    assert i.__hash__() == hash(i)
-
-    def test_path(self):
-        path = Path([set(["a", "b"]), set(["c", "b"]), set([])], [1, Vertex(1), "hello"])
-        assert "path[1, v[1], hello]" == str(path)
-        assert 1 == path["a"]
-        assert Vertex(1) == path["c"]
-        assert [1, Vertex(1)] == path["b"]
-        assert path[0] == 1
-        assert path[1] == Vertex(1)
-        assert path[2] == "hello"
-        assert 3 == len(path)
-        assert "hello" in path
-        assert "goodbye" not in path
-        assert Vertex(1) in path
-        assert Vertex(123) not in path
-        #
-        try:
-            temp = path[3]
-            raise Exception("Accessing beyond the list index should throw an index error")
-        except IndexError:
-            pass
-        #
-        try:
-            temp = path["zz"]
-            raise Exception("Accessing nothing should throw a key error")
-        except KeyError:
-            pass
-        #
-        try:
-            temp = path[1:2]
-            raise Exception("Accessing using slices should throw a type error")
-        except TypeError:
-            pass
-        #
-        assert path == path
-        assert hash(path) == hash(path)
-        path2 = Path([set(["a", "b"]), set(["c", "b"]), set([])], [1, Vertex(1), "hello"])
-        assert path == path2
-        assert hash(path) == hash(path2)
-        assert path != Path([set(["a"]), set(["c", "b"]), set([])], [1, Vertex(1), "hello"])
-        assert path != Path([set(["a", "b"]), set(["c", "b"]), set([])], [3, Vertex(1), "hello"])
diff --git a/gremlin-python/src/main/jython/LICENSE b/gremlin-python/src/main/python/LICENSE
similarity index 100%
rename from gremlin-python/src/main/jython/LICENSE
rename to gremlin-python/src/main/python/LICENSE
diff --git a/gremlin-python/src/main/jython/MANIFEST.in b/gremlin-python/src/main/python/MANIFEST.in
similarity index 100%
rename from gremlin-python/src/main/jython/MANIFEST.in
rename to gremlin-python/src/main/python/MANIFEST.in
diff --git a/gremlin-python/src/main/jython/NOTICE b/gremlin-python/src/main/python/NOTICE
similarity index 100%
rename from gremlin-python/src/main/jython/NOTICE
rename to gremlin-python/src/main/python/NOTICE
diff --git a/gremlin-python/src/main/jython/README.rst b/gremlin-python/src/main/python/README.rst
similarity index 100%
rename from gremlin-python/src/main/jython/README.rst
rename to gremlin-python/src/main/python/README.rst
diff --git a/gremlin-python/src/main/jython/example.py b/gremlin-python/src/main/python/example.py
similarity index 100%
rename from gremlin-python/src/main/jython/example.py
rename to gremlin-python/src/main/python/example.py
diff --git a/gremlin-python/src/main/jython/gremlin_python/__init__.py b/gremlin-python/src/main/python/gremlin_python/__init__.py
similarity index 100%
rename from gremlin-python/src/main/jython/gremlin_python/__init__.py
rename to gremlin-python/src/main/python/gremlin_python/__init__.py
diff --git a/gremlin-python/src/main/jython/gremlin_python/driver/__init__.py b/gremlin-python/src/main/python/gremlin_python/driver/__init__.py
similarity index 100%
rename from gremlin-python/src/main/jython/gremlin_python/driver/__init__.py
rename to gremlin-python/src/main/python/gremlin_python/driver/__init__.py
diff --git a/gremlin-python/src/main/python/gremlin_python/driver/aiohttp/__init__.py b/gremlin-python/src/main/python/gremlin_python/driver/aiohttp/__init__.py
new file mode 100644
index 0000000..ef62ce5
--- /dev/null
+++ b/gremlin-python/src/main/python/gremlin_python/driver/aiohttp/__init__.py
@@ -0,0 +1,18 @@
+#
+# 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.
+#
diff --git a/gremlin-python/src/main/python/gremlin_python/driver/aiohttp/transport.py b/gremlin-python/src/main/python/gremlin_python/driver/aiohttp/transport.py
new file mode 100644
index 0000000..a964ae6
--- /dev/null
+++ b/gremlin-python/src/main/python/gremlin_python/driver/aiohttp/transport.py
@@ -0,0 +1,135 @@
+#
+# 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.
+#
+
+
+import aiohttp
+import asyncio
+import async_timeout
+from aiohttp import ClientResponseError
+
+from gremlin_python.driver.transport import AbstractBaseTransport
+
+__author__ = 'Lyndon Bauto (lyndonb@bitquilltech.com)'
+
+
+class AiohttpTransport(AbstractBaseTransport):
+    nest_asyncio_applied = False
+
+    # Default heartbeat of 5.0 seconds.
+    def __init__(self, call_from_event_loop=None, read_timeout=None, write_timeout=None, **kwargs):
+        if call_from_event_loop is not None and call_from_event_loop and not AiohttpTransport.nest_asyncio_applied:
+            """ 
+                The AiohttpTransport implementation uses the asyncio event loop. Because of this, it cannot be called within an
+                event loop without nest_asyncio. If the code is ever refactored so that it can be called within an event loop
+                this import and call can be removed. Without this, applications which use the event loop to call gremlin-python
+                (such as Jupyter) will not work.
+            """
+            import nest_asyncio
+            nest_asyncio.apply()
+            AiohttpTransport.nest_asyncio_applied = True
+
+        # Start event loop and initialize websocket and client to None
+        self._loop = asyncio.new_event_loop()
+        self._websocket = None
+        self._client_session = None
+
+        # Set all inner variables to parameters passed in.
+        self._aiohttp_kwargs = kwargs
+        self._write_timeout = write_timeout
+        self._read_timeout = read_timeout
+        if "max_content_length" in self._aiohttp_kwargs:
+            self._aiohttp_kwargs["max_msg_size"] = self._aiohttp_kwargs.pop("max_content_length")
+        if "ssl_options" in self._aiohttp_kwargs:
+            self._aiohttp_kwargs["ssl"] = self._aiohttp_kwargs.pop("ssl_options")
+
+    def connect(self, url, headers=None):
+        # Inner function to perform async connect.
+        async def async_connect():
+            # Start client session and use it to create a websocket with all the connection options provided.
+            self._client_session = aiohttp.ClientSession(loop=self._loop)
+            try:
+                self._websocket = await self._client_session.ws_connect(url, **self._aiohttp_kwargs, headers=headers)
+            except ClientResponseError as err:
+                # If 403, just send forbidden because in some cases this prints out a huge verbose message
+                # that includes credentials.
+                if err.status == 403:
+                    raise Exception('Failed to connect to server: HTTP Error code 403 - Forbidden.')
+                else:
+                    raise
+
+        # Execute the async connect synchronously.
+        self._loop.run_until_complete(async_connect())
+
+    def write(self, message):
+        # Inner function to perform async write.
+        async def async_write():
+            async with async_timeout.timeout(self._write_timeout):
+                await self._websocket.send_bytes(message)
+
+        # Execute the async write synchronously.
+        self._loop.run_until_complete(async_write())
+
+    def read(self):
+        # Inner function to perform async read.
+        async def async_read():
+            async with async_timeout.timeout(self._read_timeout):
+                return await self._websocket.receive()
+
+        # Execute the async read synchronously.
+        msg = self._loop.run_until_complete(async_read())
+
+        # Need to handle multiple potential message types.
+        if msg.type == aiohttp.WSMsgType.close:
+            # Server is closing connection, shutdown and throw exception.
+            self.close()
+            raise RuntimeError("Connection was closed by server.")
+        elif msg.type == aiohttp.WSMsgType.closed:
+            # Should not be possible since our loop and socket would be closed.
+            raise RuntimeError("Connection was already closed.")
+        elif msg.type == aiohttp.WSMsgType.error:
+            # Error on connection, try to convert message to a string in error.
+            raise RuntimeError("Received error on read: '" + str(msg.data) + "'")
+        elif msg.type == aiohttp.WSMsgType.text:
+            # Convert message to bytes.
+            data = msg.data.strip().encode('utf-8')
+        else:
+            # General handle, return byte data.
+            data = msg.data
+        return data
+
+    def close(self):
+        # Inner function to perform async close.
+        async def async_close():
+            if not self._websocket.closed:
+                await self._websocket.close()
+            if not self._client_session.closed:
+                await self._client_session.close()
+
+        # If the loop is not closed (connection hasn't already been closed)
+        if not self._loop.is_closed():
+            # Execute the async close synchronously.
+            self._loop.run_until_complete(async_close())
+
+            # Close the event loop.
+            self._loop.close()
+
+    @property
+    def closed(self):
+        # Connection is closed if either the websocket or the client session is closed.
+        return self._websocket.closed or self._client_session.closed
diff --git a/gremlin-python/src/main/python/gremlin_python/driver/client.py b/gremlin-python/src/main/python/gremlin_python/driver/client.py
new file mode 100644
index 0000000..8b6a53b
--- /dev/null
+++ b/gremlin-python/src/main/python/gremlin_python/driver/client.py
@@ -0,0 +1,153 @@
+#
+# 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.
+#
+from concurrent.futures import ThreadPoolExecutor
+
+from six.moves import queue
+
+from gremlin_python.driver import connection, protocol, request, serializer
+from gremlin_python.process import traversal
+
+# This is until concurrent.futures backport 3.1.0 release
+try:
+    from multiprocessing import cpu_count
+except ImportError:
+    # some platforms don't have multiprocessing
+    def cpu_count():
+        return None
+
+__author__ = 'David M. Brown (davebshow@gmail.com)'
+
+
+class Client:
+
+    def __init__(self, url, traversal_source, protocol_factory=None,
+                 transport_factory=None, pool_size=None, max_workers=None,
+                 message_serializer=None, username="", password="",
+                 kerberized_service="", headers=None, session="",
+                 **transport_kwargs):
+        self._url = url
+        self._headers = headers
+        self._traversal_source = traversal_source
+        if "max_content_length" not in transport_kwargs:
+            transport_kwargs["max_content_length"] = 10 * 1024 * 1024
+        if message_serializer is None:
+            message_serializer = serializer.GraphSONSerializersV3d0()
+        self._message_serializer = message_serializer
+        self._username = username
+        self._password = password
+        self._session = session
+        self._sessionEnabled = (session != "")
+        if transport_factory is None:
+            try:
+                from gremlin_python.driver.aiohttp.transport import (
+                    AiohttpTransport)
+            except ImportError:
+                raise Exception("Please install AIOHTTP or pass "
+                                "custom transport factory")
+            else:
+                def transport_factory():
+                    return AiohttpTransport(**transport_kwargs)
+        self._transport_factory = transport_factory
+        if protocol_factory is None:
+            def protocol_factory(): return protocol.GremlinServerWSProtocol(
+                self._message_serializer,
+                username=self._username,
+                password=self._password,
+                kerberized_service=kerberized_service)
+        self._protocol_factory = protocol_factory
+        if self._sessionEnabled:
+            if pool_size is None:
+                pool_size = 1
+            elif pool_size != 1:
+                raise Exception("PoolSize must be 1 on session mode!")
+        if pool_size is None:
+            pool_size = 4
+        self._pool_size = pool_size
+        # This is until concurrent.futures backport 3.1.0 release
+        if max_workers is None:
+            # If your application is overlapping Gremlin I/O on multiple threads
+            # consider passing kwarg max_workers = (cpu_count() or 1) * 5
+            max_workers = pool_size
+        self._executor = ThreadPoolExecutor(max_workers=max_workers)
+        # Threadsafe queue
+        self._pool = queue.Queue()
+        self._fill_pool()
+
+    @property
+    def available_pool_size(self):
+        return self._pool.qsize()
+
+    @property
+    def executor(self):
+        return self._executor
+
+    @property
+    def traversal_source(self):
+        return self._traversal_source
+
+    def _fill_pool(self):
+        for i in range(self._pool_size):
+            conn = self._get_connection()
+            self._pool.put_nowait(conn)
+
+    def close(self):
+        if self._sessionEnabled:
+            self._close_session()
+        while not self._pool.empty():
+            conn = self._pool.get(True)
+            conn.close()
+        self._executor.shutdown()
+
+    def _close_session(self):
+        message = request.RequestMessage(
+            processor='session', op='close',
+            args={'session': self._session})
+        conn = self._pool.get(True)
+        return conn.write(message).result()
+
+    def _get_connection(self):
+        protocol = self._protocol_factory()
+        return connection.Connection(
+            self._url, self._traversal_source, protocol,
+            self._transport_factory, self._executor, self._pool,
+            headers=self._headers)
+
+    def submit(self, message, bindings=None, request_options=None):
+        return self.submitAsync(message, bindings=bindings, request_options=request_options).result()
+
+    def submitAsync(self, message, bindings=None, request_options=None):
+        if isinstance(message, traversal.Bytecode):
+            message = request.RequestMessage(
+                processor='traversal', op='bytecode',
+                args={'gremlin': message,
+                      'aliases': {'g': self._traversal_source}})
+        elif isinstance(message, str):
+            message = request.RequestMessage(
+                processor='', op='eval',
+                args={'gremlin': message,
+                      'aliases': {'g': self._traversal_source}})
+            if bindings:
+                message.args.update({'bindings': bindings})
+            if self._sessionEnabled:
+                message = message._replace(processor='session')
+                message.args.update({'session': self._session})
+        conn = self._pool.get(True)
+        if request_options:
+            message.args.update(request_options)
+        return conn.write(message)
diff --git a/gremlin-python/src/main/jython/gremlin_python/driver/connection.py b/gremlin-python/src/main/python/gremlin_python/driver/connection.py
similarity index 100%
rename from gremlin-python/src/main/jython/gremlin_python/driver/connection.py
rename to gremlin-python/src/main/python/gremlin_python/driver/connection.py
diff --git a/gremlin-python/src/main/python/gremlin_python/driver/driver_remote_connection.py b/gremlin-python/src/main/python/gremlin_python/driver/driver_remote_connection.py
new file mode 100644
index 0000000..d5e4660
--- /dev/null
+++ b/gremlin-python/src/main/python/gremlin_python/driver/driver_remote_connection.py
@@ -0,0 +1,87 @@
+#
+# 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.
+#
+from concurrent.futures import Future
+
+from gremlin_python.driver import client, serializer
+from gremlin_python.driver.remote_connection import (
+    RemoteConnection, RemoteTraversal)
+from gremlin_python.process.strategies import OptionsStrategy
+
+__author__ = 'David M. Brown (davebshow@gmail.com)'
+
+
+class DriverRemoteConnection(RemoteConnection):
+
+    def __init__(self, url, traversal_source, protocol_factory=None,
+                 transport_factory=None, pool_size=None, max_workers=None,
+                 username="", password="", kerberized_service='',
+                 message_serializer=None, graphson_reader=None,
+                 graphson_writer=None, headers=None,
+                 **transport_kwargs):
+        if message_serializer is None:
+            message_serializer = serializer.GraphSONMessageSerializer(
+                reader=graphson_reader,
+                writer=graphson_writer)
+        self._client = client.Client(url, traversal_source,
+                                     protocol_factory=protocol_factory,
+                                     transport_factory=transport_factory,
+                                     pool_size=pool_size,
+                                     max_workers=max_workers,
+                                     message_serializer=message_serializer,
+                                     username=username,
+                                     password=password,
+                                     kerberized_service=kerberized_service,
+                                     headers=headers,
+                                     **transport_kwargs)
+        self._url = self._client._url
+        self._traversal_source = self._client._traversal_source
+
+    def close(self):
+        self._client.close()
+
+    def submit(self, bytecode):
+        result_set = self._client.submit(bytecode, request_options=self._extract_request_options(bytecode))
+        results = result_set.all().result()
+        return RemoteTraversal(iter(results))
+
+    def submitAsync(self, bytecode):
+        future = Future()
+        future_result_set = self._client.submitAsync(bytecode, request_options=self._extract_request_options(bytecode))
+
+        def cb(f):
+            try:
+                result_set = f.result()
+                results = result_set.all().result()
+                future.set_result(RemoteTraversal(iter(results)))
+            except Exception as e:
+                future.set_exception(e)
+
+        future_result_set.add_done_callback(cb)
+        return future
+
+    @staticmethod
+    def _extract_request_options(bytecode):
+        options_strategy = next((x for x in bytecode.source_instructions
+                                 if x[0] == "withStrategies" and type(x[1]) is OptionsStrategy), None)
+        request_options = None
+        if options_strategy:
+            allowed_keys = ['evaluationTimeout', 'scriptEvaluationTimeout', 'batchSize', 'requestId', 'userAgent']
+            request_options = {allowed: options_strategy[1].configuration[allowed] for allowed in allowed_keys
+                               if allowed in options_strategy[1].configuration}
+        return request_options
diff --git a/gremlin-python/src/main/python/gremlin_python/driver/protocol.py b/gremlin-python/src/main/python/gremlin_python/driver/protocol.py
new file mode 100644
index 0000000..74773b8
--- /dev/null
+++ b/gremlin-python/src/main/python/gremlin_python/driver/protocol.py
@@ -0,0 +1,185 @@
+#
+# 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.
+#
+import abc
+import base64
+import struct
+
+# import kerberos    Optional dependency imported in relevant codeblock
+import six
+
+try:
+    import ujson as json
+except ImportError:
+    import json
+
+from gremlin_python.driver import request
+from gremlin_python.driver.resultset import ResultSet
+
+__author__ = 'David M. Brown (davebshow@gmail.com)'
+
+
+class GremlinServerError(Exception):
+    def __init__(self, status):
+        super(GremlinServerError, self).__init__('{0}: {1}'.format(status['code'], status['message']))
+        self._status_attributes = status['attributes']
+        self.status_code = status['code']
+
+    @property
+    def status_attributes(self):
+        return self._status_attributes
+
+
+class ConfigurationError(Exception):
+    pass
+
+
+@six.add_metaclass(abc.ABCMeta)
+class AbstractBaseProtocol:
+
+    @abc.abstractmethod
+    def connection_made(self, transport):
+        self._transport = transport
+
+    @abc.abstractmethod
+    def data_received(self, message, results_dict):
+        pass
+
+    @abc.abstractmethod
+    def write(self, request_id, request_message):
+        pass
+
+
+class GremlinServerWSProtocol(AbstractBaseProtocol):
+
+    MAX_CONTENT_LENGTH = 65536
+    QOP_AUTH_BIT = 1
+    _kerberos_context = None
+
+    def __init__(self, message_serializer, username='', password='', kerberized_service=''):
+        self._message_serializer = message_serializer
+        self._username = username
+        self._password = password
+        self._kerberized_service = kerberized_service
+
+    def connection_made(self, transport):
+        super(GremlinServerWSProtocol, self).connection_made(transport)
+
+    def write(self, request_id, request_message):
+        message = self._message_serializer.serialize_message(
+            request_id, request_message)
+        self._transport.write(message)
+
+    def data_received(self, message, results_dict):
+        # if Gremlin Server cuts off then we get a None for the message
+        if message is None:
+            raise GremlinServerError({'code': 500,
+                                      'message': 'Server disconnected - please try to reconnect', 'attributes': {}})
+
+        message = self._message_serializer.deserialize_message(message)
+        request_id = message['requestId']
+        result_set = results_dict[request_id] if request_id in results_dict else ResultSet(None, None)
+        status_code = message['status']['code']
+        aggregate_to = message['result']['meta'].get('aggregateTo', 'list')
+        data = message['result']['data']
+        result_set.aggregate_to = aggregate_to
+        if status_code == 407:
+            if self._username and self._password:
+                auth_bytes = b''.join([b'\x00', self._username.encode('utf-8'),
+                                       b'\x00', self._password.encode('utf-8')])
+                auth = base64.b64encode(auth_bytes)
+                request_message = request.RequestMessage(
+                    'traversal', 'authentication', {'sasl': auth.decode()})
+            elif self._kerberized_service:
+                request_message = self._kerberos_received(message)
+            else:
+                raise ConfigurationError(
+                    'Gremlin server requires authentication credentials in DriverRemoteConnection.'
+                    'For basic authentication provide username and password. '
+                    'For kerberos authentication provide the kerberized_service parameter.')
+            self.write(request_id, request_message)
+            data = self._transport.read()
+            # Allow for auth handshake with multiple steps
+            return self.data_received(data, results_dict)
+        elif status_code == 204:
+            result_set.stream.put_nowait([])
+            del results_dict[request_id]
+            return status_code
+        elif status_code in [200, 206]:
+            result_set.stream.put_nowait(data)
+            if status_code == 200:
+                result_set.status_attributes = message['status']['attributes']
+                del results_dict[request_id]
+            return status_code
+        else:
+            del results_dict[request_id]
+            raise GremlinServerError(message['status'])
+
+    def _kerberos_received(self, message):
+        # Inspired by: https://github.com/thobbs/pure-sasl/blob/0.6.2/puresasl/mechanisms.py
+        #              https://github.com/thobbs/pure-sasl/blob/0.6.2/LICENSE
+        try:
+            import kerberos
+        except ImportError:
+            raise ImportError('Please install gremlinpython[kerberos].')
+
+        # First pass: get service granting ticket and return it to gremlin-server
+        if not self._kerberos_context:
+            try:
+                _, kerberos_context = kerberos.authGSSClientInit(
+                    self._kerberized_service, gssflags=kerberos.GSS_C_MUTUAL_FLAG)
+                kerberos.authGSSClientStep(kerberos_context, '')
+                auth = kerberos.authGSSClientResponse(kerberos_context)
+                self._kerberos_context = kerberos_context
+            except kerberos.KrbError as e:
+                raise ConfigurationError(
+                    'Kerberos authentication requires a valid service name in DriverRemoteConnection, '
+                    'as well as a valid tgt (export KRB5CCNAME) or keytab (export KRB5_KTNAME): ' + str(e))
+            return request.RequestMessage('', 'authentication', {'sasl': auth})
+
+        # Second pass: completion of authentication
+        sasl_response = message['status']['attributes']['sasl']
+        if not self._username:
+            result_code = kerberos.authGSSClientStep(self._kerberos_context, sasl_response)
+            if result_code == kerberos.AUTH_GSS_COMPLETE:
+                self._username = kerberos.authGSSClientUserName(self._kerberos_context)
+            return request.RequestMessage('', 'authentication', {'sasl': ''})
+
+        # Third pass: sasl quality of protection (qop) handshake
+
+        # Gremlin-server Krb5Authenticator only supports qop=QOP_AUTH; use ssl for confidentiality.
+        # Handshake content format:
+        # byte 0: the selected qop. 1==auth, 2==auth-int, 4==auth-conf
+        # byte 1-3: the max length for any buffer sent back and forth on this connection. (big endian)
+        # the rest of the buffer: the authorization user name in UTF-8 - not null terminated.
+        kerberos.authGSSClientUnwrap(self._kerberos_context, sasl_response)
+        data = kerberos.authGSSClientResponse(self._kerberos_context)
+        plaintext_data = base64.b64decode(data)
+        assert len(plaintext_data) == 4, "Unexpected response from gremlin server sasl handshake"
+        word, = struct.unpack('!I', plaintext_data)
+        qop_bits = word >> 24
+        assert self.QOP_AUTH_BIT & qop_bits, "Unexpected sasl qop level received from gremlin server"
+
+        name_length = len(self._username)
+        fmt = '!I' + str(name_length) + 's'
+        word = self.QOP_AUTH_BIT << 24 | self.MAX_CONTENT_LENGTH
+        out = struct.pack(fmt, word, self._username.encode("utf-8"),)
+        encoded = base64.b64encode(out).decode('ascii')
+        kerberos.authGSSClientWrap(self._kerberos_context, encoded)
+        auth = kerberos.authGSSClientResponse(self._kerberos_context)
+        return request.RequestMessage('', 'authentication', {'sasl': auth})
diff --git a/gremlin-python/src/main/python/gremlin_python/driver/remote_connection.py b/gremlin-python/src/main/python/gremlin_python/driver/remote_connection.py
new file mode 100644
index 0000000..667354e
--- /dev/null
+++ b/gremlin-python/src/main/python/gremlin_python/driver/remote_connection.py
@@ -0,0 +1,70 @@
+#
+# 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.
+#
+import abc
+import six
+
+from gremlin_python.driver import request
+from gremlin_python.process import traversal
+
+__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
+
+
+@six.add_metaclass(abc.ABCMeta)
+class RemoteConnection(object):
+    def __init__(self, url, traversal_source):
+        self._url = url
+        self._traversal_source = traversal_source
+
+    @property
+    def url(self):
+        return self._url
+
+    @property
+    def traversal_source(self):
+        return self._traversal_source
+
+    @abc.abstractmethod
+    def submit(self, bytecode):
+        pass
+
+    def __repr__(self):
+        return "remoteconnection[" + self._url + "," + self._traversal_source + "]"
+
+
+class RemoteTraversal(traversal.Traversal):
+    def __init__(self, traversers):
+        super(RemoteTraversal, self).__init__(None, None, None)
+        self.traversers = traversers
+
+
+class RemoteStrategy(traversal.TraversalStrategy):
+    def __init__(self, remote_connection):
+        traversal.TraversalStrategy.__init__(self)
+        self.remote_connection = remote_connection
+
+    def apply(self, traversal):
+        if traversal.traversers is None:
+            remote_traversal = self.remote_connection.submit(traversal.bytecode)
+            traversal.remote_results = remote_traversal
+            traversal.traversers = remote_traversal.traversers
+
+    def apply_async(self, traversal):
+        if traversal.traversers is None:
+            traversal.remote_results = self.remote_connection.submitAsync(
+                traversal.bytecode)
diff --git a/gremlin-python/src/main/jython/gremlin_python/driver/request.py b/gremlin-python/src/main/python/gremlin_python/driver/request.py
similarity index 100%
rename from gremlin-python/src/main/jython/gremlin_python/driver/request.py
rename to gremlin-python/src/main/python/gremlin_python/driver/request.py
diff --git a/gremlin-python/src/main/jython/gremlin_python/driver/resultset.py b/gremlin-python/src/main/python/gremlin_python/driver/resultset.py
similarity index 100%
rename from gremlin-python/src/main/jython/gremlin_python/driver/resultset.py
rename to gremlin-python/src/main/python/gremlin_python/driver/resultset.py
diff --git a/gremlin-python/src/main/python/gremlin_python/driver/serializer.py b/gremlin-python/src/main/python/gremlin_python/driver/serializer.py
new file mode 100644
index 0000000..6818dc9
--- /dev/null
+++ b/gremlin-python/src/main/python/gremlin_python/driver/serializer.py
@@ -0,0 +1,276 @@
+#
+# 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.
+#
+try:
+    import ujson as json
+except ImportError:
+    import json
+import struct
+import uuid
+import io
+
+from gremlin_python.structure.io import graphbinaryV1
+from gremlin_python.structure.io import graphsonV2d0
+from gremlin_python.structure.io import graphsonV3d0
+
+__author__ = 'David M. Brown (davebshow@gmail.com)'
+
+
+class Processor:
+    """Base class for OpProcessor serialization system."""
+
+    def __init__(self, writer):
+        self._writer = writer
+
+    def get_op_args(self, op, args):
+        op_method = getattr(self, op, None)
+        if not op_method:
+            raise Exception("Processor does not support op: {}".format(op))
+        return op_method(args)
+
+
+class Standard(Processor):
+
+    def authentication(self, args):
+        return args
+
+    def eval(self, args):
+        return args
+
+
+class Session(Processor):
+
+    def authentication(self, args):
+        return args
+
+    def eval(self, args):
+        return args
+
+    def close(self, args):
+        return args
+
+class Traversal(Processor):
+
+    def authentication(self, args):
+        return args
+
+    def bytecode(self, args):
+        gremlin = args['gremlin']
+        args['gremlin'] = self._writer.toDict(gremlin)
+        aliases = args.get('aliases', '')
+        if not aliases:
+            aliases = {'g': 'g'}
+        args['aliases'] = aliases
+        return args
+
+
+class GraphSONMessageSerializer(object):
+    """
+    Message serializer for GraphSON. Allow users to pass custom reader,
+    writer, and version kwargs for custom serialization. Otherwise,
+    use current GraphSON version as default.
+    """
+
+    # KEEP TRACK OF CURRENT DEFAULTS
+    DEFAULT_READER_CLASS = graphsonV3d0.GraphSONReader
+    DEFAULT_WRITER_CLASS = graphsonV3d0.GraphSONWriter
+    DEFAULT_VERSION = b"application/vnd.gremlin-v3.0+json"
+
+    def __init__(self, reader=None, writer=None, version=None):
+        if not version:
+            version = self.DEFAULT_VERSION
+        self._version = version
+        if not reader:
+            reader = self.DEFAULT_READER_CLASS()
+        self._graphson_reader = reader
+        if not writer:
+            writer = self.DEFAULT_WRITER_CLASS()
+        self.standard = Standard(writer)
+        self.traversal = Traversal(writer)
+        self.session = Session(writer)
+
+    @property
+    def version(self):
+        """Read only property"""
+        return self._version
+
+    def get_processor(self, processor):
+        processor = getattr(self, processor, None)
+        if not processor:
+            raise Exception("Unknown processor")
+        return processor
+
+    def serialize_message(self, request_id, request_message):
+        processor = request_message.processor
+        op = request_message.op
+        args = request_message.args
+        if not processor:
+            processor_obj = self.get_processor('standard')
+        else:
+            processor_obj = self.get_processor(processor)
+        args = processor_obj.get_op_args(op, args)
+        message = self.build_message(request_id, processor, op, args)
+        return message
+
+    def build_message(self, request_id, processor, op, args):
+        message = {
+            'requestId': {'@type': 'g:UUID', '@value': request_id},
+            'processor': processor,
+            'op': op,
+            'args': args
+        }
+        return self.finalize_message(message, b"\x21", self.version)
+
+    def finalize_message(self, message, mime_len, mime_type):
+        message = json.dumps(message)
+        message = b''.join([mime_len, mime_type, message.encode('utf-8')])
+        return message
+
+    def deserialize_message(self, message):
+        msg = json.loads(message.decode('utf-8'))
+        return self._graphson_reader.toObject(msg)
+
+
+class GraphSONSerializersV2d0(GraphSONMessageSerializer):
+    """Message serializer for GraphSON 2.0"""
+    def __init__(self):
+        reader = graphsonV2d0.GraphSONReader()
+        writer = graphsonV2d0.GraphSONWriter()
+        version = b"application/vnd.gremlin-v2.0+json"
+        super(GraphSONSerializersV2d0, self).__init__(reader, writer, version)
+
+
+class GraphSONSerializersV3d0(GraphSONMessageSerializer):
+    """Message serializer for GraphSON 3.0"""
+    def __init__(self):
+        reader = graphsonV3d0.GraphSONReader()
+        writer = graphsonV3d0.GraphSONWriter()
+        version = b"application/vnd.gremlin-v3.0+json"
+        super(GraphSONSerializersV3d0, self).__init__(reader, writer, version)
+
+
+class GraphBinarySerializersV1(object):
+    DEFAULT_READER_CLASS = graphbinaryV1.GraphBinaryReader
+    DEFAULT_WRITER_CLASS = graphbinaryV1.GraphBinaryWriter
+    DEFAULT_VERSION = b"application/vnd.graphbinary-v1.0"
+
+    max_int64 = 0xFFFFFFFFFFFFFFFF
+    header_struct = struct.Struct('>b32sBQQ')
+    header_pack = header_struct.pack
+    int_pack = graphbinaryV1.int32_pack
+    int32_unpack = struct.Struct(">i").unpack
+
+    def __init__(self, reader=None, writer=None, version=None):
+        if not version:
+            version = self.DEFAULT_VERSION
+        self._version = version
+        if not reader:
+            reader = self.DEFAULT_READER_CLASS()
+        self._graphbinary_reader = reader
+        if not writer:
+            writer = self.DEFAULT_WRITER_CLASS()
+        self._graphbinary_writer = writer
+        self.standard = Standard(writer)
+        self.traversal = Traversal(writer)
+
+    @property
+    def version(self):
+        """Read only property"""
+        return self._version
+
+    def get_processor(self, processor):
+        processor = getattr(self, processor, None)
+        if not processor:
+            raise Exception("Unknown processor")
+        return processor
+
+    def serialize_message(self, request_id, request_message):
+        processor = request_message.processor
+        op = request_message.op
+        args = request_message.args
+        if not processor:
+            processor_obj = self.get_processor('standard')
+        else:
+            processor_obj = self.get_processor(processor)
+        args = processor_obj.get_op_args(op, args)
+        message = self.build_message(request_id, processor, op, args)
+        return message
+
+    def build_message(self, request_id, processor, op, args):
+        message = {
+            'requestId': request_id,
+            'processor': processor,
+            'op': op,
+            'args': args
+        }
+        return self.finalize_message(message, 0x20, self.version)
+
+    def finalize_message(self, message, mime_len, mime_type):
+        ba = bytearray()
+
+        request_id = uuid.UUID(message['requestId'])
+        ba.extend(self.header_pack(mime_len, mime_type, 0x81,
+                                   (request_id.int >> 64) & self.max_int64, request_id.int & self.max_int64))
+
+        op_bytes = message['op'].encode("utf-8")
+        ba.extend(self.int_pack(len(op_bytes)))
+        ba.extend(op_bytes)
+
+        processor_bytes = message['processor'].encode("utf-8")
+        ba.extend(self.int_pack(len(processor_bytes)))
+        ba.extend(processor_bytes)
+
+        args = message["args"]
+        ba.extend(self.int_pack(len(args)))
+        for k, v in args.items():
+            self._graphbinary_writer.toDict(k, ba)
+
+            # processor_obj.get_op_args in serialize_message() seems to already handle bytecode. in python 3
+            # because bytearray isn't bound to a type in graphbinary it falls through the writeObject() and
+            # just works but python 2 bytearray is bound to ByteBufferType so it writes DataType.bytebuffer
+            # rather than DataType.bytecode and the server gets confused. special casing this for now until
+            # it can be refactored
+            if k == "gremlin":
+                ba.extend(v)
+            else:
+                self._graphbinary_writer.toDict(v, ba)
+
+        return bytes(ba)
+
+    def deserialize_message(self, message):
+        b = io.BytesIO(message)
+
+        b.read(1)  # version
+
+        request_id = str(self._graphbinary_reader.toObject(b, graphbinaryV1.DataType.uuid))
+        status_code = self.int32_unpack(b.read(4))[0]
+        status_msg = self._graphbinary_reader.toObject(b, graphbinaryV1.DataType.string)
+        status_attrs = self._graphbinary_reader.toObject(b, graphbinaryV1.DataType.map, nullable=False)
+        meta_attrs = self._graphbinary_reader.toObject(b, graphbinaryV1.DataType.map, nullable=False)
+        result = self._graphbinary_reader.toObject(b)
+
+        b.close()
+
+        msg = {'requestId': request_id,
+               'status': {'code': status_code,
+                          'message': status_msg,
+                          'attributes': status_attrs},
+               'result': {'meta': meta_attrs,
+                          'data': result}}
+
+        return msg
diff --git a/gremlin-python/src/main/python/gremlin_python/driver/transport.py b/gremlin-python/src/main/python/gremlin_python/driver/transport.py
new file mode 100644
index 0000000..e7535e0
--- /dev/null
+++ b/gremlin-python/src/main/python/gremlin_python/driver/transport.py
@@ -0,0 +1,47 @@
+#
+# 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.
+#
+import abc
+import six
+
+__author__ = 'David M. Brown (davebshow@gmail.com)'
+
+
+@six.add_metaclass(abc.ABCMeta)
+class AbstractBaseTransport:
+
+    @abc.abstractmethod
+    def connect(self, url, headers=None):
+        pass
+
+    @abc.abstractmethod
+    def write(self, message):
+        pass
+
+    @abc.abstractmethod
+    def read(self):
+        pass
+
+    @abc.abstractmethod
+    def close(self):
+        pass
+
+    @property
+    @abc.abstractmethod
+    def closed(self):
+        pass
diff --git a/gremlin-python/src/main/jython/gremlin_python/process/__init__.py b/gremlin-python/src/main/python/gremlin_python/process/__init__.py
similarity index 100%
rename from gremlin-python/src/main/jython/gremlin_python/process/__init__.py
rename to gremlin-python/src/main/python/gremlin_python/process/__init__.py
diff --git a/gremlin-python/src/main/jython/gremlin_python/process/anonymous_traversal.py b/gremlin-python/src/main/python/gremlin_python/process/anonymous_traversal.py
similarity index 100%
rename from gremlin-python/src/main/jython/gremlin_python/process/anonymous_traversal.py
rename to gremlin-python/src/main/python/gremlin_python/process/anonymous_traversal.py
diff --git a/gremlin-python/src/main/python/gremlin_python/process/graph_traversal.py b/gremlin-python/src/main/python/gremlin_python/process/graph_traversal.py
new file mode 100644
index 0000000..698056f
--- /dev/null
+++ b/gremlin-python/src/main/python/gremlin_python/process/graph_traversal.py
@@ -0,0 +1,1580 @@
+#
+# 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.
+#
+
+import sys
+import copy
+from .traversal import Traversal
+from .traversal import TraversalStrategies
+from .strategies import VertexProgramStrategy, OptionsStrategy
+from .traversal import Bytecode
+from ..driver.remote_connection import RemoteStrategy
+from .. import statics
+from ..statics import long
+
+
+class GraphTraversalSource(object):
+    def __init__(self, graph, traversal_strategies, bytecode=None):
+        self.graph = graph
+        self.traversal_strategies = traversal_strategies
+        if bytecode is None:
+          bytecode = Bytecode()
+        self.bytecode = bytecode
+        self.graph_traversal = GraphTraversal
+
+    def __repr__(self):
+        return "graphtraversalsource[" + str(self.graph) + "]"
+
+    def get_graph_traversal_source(self):
+        return self.__class__(self.graph, TraversalStrategies(self.traversal_strategies), Bytecode(self.bytecode))
+
+    def get_graph_traversal(self):
+        return self.graph_traversal(self.graph, self.traversal_strategies, Bytecode(self.bytecode))
+
+    def withBulk(self, *args):
+        source = self.get_graph_traversal_source()
+        source.bytecode.add_source("withBulk", *args)
+        return source
+
+    def withPath(self, *args):
+        source = self.get_graph_traversal_source()
+        source.bytecode.add_source("withPath", *args)
+        return source
+
+    def withSack(self, *args):
+        source = self.get_graph_traversal_source()
+        source.bytecode.add_source("withSack", *args)
+        return source
+
+    def withSideEffect(self, *args):
+        source = self.get_graph_traversal_source()
+        source.bytecode.add_source("withSideEffect", *args)
+        return source
+
+    def withStrategies(self, *args):
+        source = self.get_graph_traversal_source()
+        source.bytecode.add_source("withStrategies", *args)
+        return source
+
+    def withoutStrategies(self, *args):
+        source = self.get_graph_traversal_source()
+        source.bytecode.add_source("withoutStrategies", *args)
+        return source
+
+    def with_(self, k, v=None):
+        source = self.get_graph_traversal_source()
+        options_strategy = next((x for x in source.bytecode.source_instructions
+                                if x[0] == "withStrategies" and type(x[1]) is OptionsStrategy), None)
+
+        val = True if v is None else v
+        if options_strategy is None:
+            options_strategy = OptionsStrategy({k: val})
+            source = self.withStrategies(options_strategy)
+        else:
+            options_strategy[1].configuration[k] = val
+
+        return source
+
+    def withRemote(self, remote_connection):
+        source = self.get_graph_traversal_source()
+        source.traversal_strategies.add_strategies([RemoteStrategy(remote_connection)])
+        return source
+
+    def withComputer(self, graph_computer=None, workers=None, result=None, persist=None, vertices=None,
+                     edges=None, configuration=None):
+        return self.withStrategies(VertexProgramStrategy(graph_computer, workers, result, persist, vertices,
+                                   edges, configuration))
+
+    def E(self, *args):
+        traversal = self.get_graph_traversal()
+        traversal.bytecode.add_step("E", *args)
+        return traversal
+
+    def V(self, *args):
+        traversal = self.get_graph_traversal()
+        traversal.bytecode.add_step("V", *args)
+        return traversal
+
+    def addE(self, *args):
+        traversal = self.get_graph_traversal()
+        traversal.bytecode.add_step("addE", *args)
+        return traversal
+
+    def addV(self, *args):
+        traversal = self.get_graph_traversal()
+        traversal.bytecode.add_step("addV", *args)
+        return traversal
+
+    def inject(self, *args):
+        traversal = self.get_graph_traversal()
+        traversal.bytecode.add_step("inject", *args)
+        return traversal
+
+    def io(self, *args):
+        traversal = self.get_graph_traversal()
+        traversal.bytecode.add_step("io", *args)
+        return traversal
+
+
+class GraphTraversal(Traversal):
+    def __init__(self, graph, traversal_strategies, bytecode):
+        super(GraphTraversal, self).__init__(graph, traversal_strategies, bytecode)
+
+    def __getitem__(self, index):
+        if isinstance(index, int):
+            return self.range(long(index), long(index + 1))
+        elif isinstance(index, slice):
+            low = long(0) if index.start is None else long(index.start)
+            high = long(sys.maxsize) if index.stop is None else long(index.stop)
+            if low == long(0):
+                return self.limit(high)
+            else:
+                return self.range(low,high)
+        else:
+            raise TypeError("Index must be int or slice")
+
+    def __getattr__(self, key):
+        if key.startswith('__'):
+            raise AttributeError(
+                'Python magic methods or keys starting with double underscore cannot be used for Gremlin sugar - prefer values(' + key + ')')
+        return self.values(key)
+
+    def clone(self):
+        return GraphTraversal(self.graph, self.traversal_strategies, copy.deepcopy(self.bytecode))
+
+    def V(self, *args):
+        self.bytecode.add_step("V", *args)
+        return self
+
+    def addE(self, *args):
+        self.bytecode.add_step("addE", *args)
+        return self
+
+    def addV(self, *args):
+        self.bytecode.add_step("addV", *args)
+        return self
+
+    def aggregate(self, *args):
+        self.bytecode.add_step("aggregate", *args)
+        return self
+
+    def and_(self, *args):
+        self.bytecode.add_step("and", *args)
+        return self
+
+    def as_(self, *args):
+        self.bytecode.add_step("as", *args)
+        return self
+
+    def barrier(self, *args):
+        self.bytecode.add_step("barrier", *args)
+        return self
+
+    def both(self, *args):
+        self.bytecode.add_step("both", *args)
+        return self
+
+    def bothE(self, *args):
+        self.bytecode.add_step("bothE", *args)
+        return self
+
+    def bothV(self, *args):
+        self.bytecode.add_step("bothV", *args)
+        return self
+
+    def branch(self, *args):
+        self.bytecode.add_step("branch", *args)
+        return self
+
+    def by(self, *args):
+        self.bytecode.add_step("by", *args)
+        return self
+
+    def cap(self, *args):
+        self.bytecode.add_step("cap", *args)
+        return self
+
+    def choose(self, *args):
+        self.bytecode.add_step("choose", *args)
+        return self
+
+    def coalesce(self, *args):
+        self.bytecode.add_step("coalesce", *args)
+        return self
+
+    def coin(self, *args):
+        self.bytecode.add_step("coin", *args)
+        return self
+
+    def connectedComponent(self, *args):
+        self.bytecode.add_step("connectedComponent", *args)
+        return self
+
+    def constant(self, *args):
+        self.bytecode.add_step("constant", *args)
+        return self
+
+    def count(self, *args):
+        self.bytecode.add_step("count", *args)
+        return self
+
+    def cyclicPath(self, *args):
+        self.bytecode.add_step("cyclicPath", *args)
+        return self
+
+    def dedup(self, *args):
+        self.bytecode.add_step("dedup", *args)
+        return self
+
+    def drop(self, *args):
+        self.bytecode.add_step("drop", *args)
+        return self
+
+    def elementMap(self, *args):
+        self.bytecode.add_step("elementMap", *args)
+        return self
+
+    def emit(self, *args):
+        self.bytecode.add_step("emit", *args)
+        return self
+
+    def filter_(self, *args):
+        self.bytecode.add_step("filter", *args)
+        return self
+
+    def flatMap(self, *args):
+        self.bytecode.add_step("flatMap", *args)
+        return self
+
+    def fold(self, *args):
+        self.bytecode.add_step("fold", *args)
+        return self
+
+    def from_(self, *args):
+        self.bytecode.add_step("from", *args)
+        return self
+
+    def group(self, *args):
+        self.bytecode.add_step("group", *args)
+        return self
+
+    def groupCount(self, *args):
+        self.bytecode.add_step("groupCount", *args)
+        return self
+
+    def has(self, *args):
+        self.bytecode.add_step("has", *args)
+        return self
+
+    def hasId(self, *args):
+        self.bytecode.add_step("hasId", *args)
+        return self
+
+    def hasKey(self, *args):
+        self.bytecode.add_step("hasKey", *args)
+        return self
+
+    def hasLabel(self, *args):
+        self.bytecode.add_step("hasLabel", *args)
+        return self
+
+    def hasNot(self, *args):
+        self.bytecode.add_step("hasNot", *args)
+        return self
+
+    def hasValue(self, *args):
+        self.bytecode.add_step("hasValue", *args)
+        return self
+
+    def id_(self, *args):
+        self.bytecode.add_step("id", *args)
+        return self
+
+    def identity(self, *args):
+        self.bytecode.add_step("identity", *args)
+        return self
+
+    def inE(self, *args):
+        self.bytecode.add_step("inE", *args)
+        return self
+
+    def inV(self, *args):
+        self.bytecode.add_step("inV", *args)
+        return self
+
+    def in_(self, *args):
+        self.bytecode.add_step("in", *args)
+        return self
+
+    def index(self, *args):
+        self.bytecode.add_step("index", *args)
+        return self
+
+    def inject(self, *args):
+        self.bytecode.add_step("inject", *args)
+        return self
+
+    def is_(self, *args):
+        self.bytecode.add_step("is", *args)
+        return self
+
+    def key(self, *args):
+        self.bytecode.add_step("key", *args)
+        return self
+
+    def label(self, *args):
+        self.bytecode.add_step("label", *args)
+        return self
+
+    def limit(self, *args):
+        self.bytecode.add_step("limit", *args)
+        return self
+
+    def local(self, *args):
+        self.bytecode.add_step("local", *args)
+        return self
+
+    def loops(self, *args):
+        self.bytecode.add_step("loops", *args)
+        return self
+
+    def map(self, *args):
+        self.bytecode.add_step("map", *args)
+        return self
+
+    def match(self, *args):
+        self.bytecode.add_step("match", *args)
+        return self
+
+    def math(self, *args):
+        self.bytecode.add_step("math", *args)
+        return self
+
+    def max_(self, *args):
+        self.bytecode.add_step("max", *args)
+        return self
+
+    def mean(self, *args):
+        self.bytecode.add_step("mean", *args)
+        return self
+
+    def min_(self, *args):
+        self.bytecode.add_step("min", *args)
+        return self
+
+    def none(self, *args):
+        self.bytecode.add_step("none", *args)
+        return self
+
+    def not_(self, *args):
+        self.bytecode.add_step("not", *args)
+        return self
+
+    def option(self, *args):
+        self.bytecode.add_step("option", *args)
+        return self
+
+    def optional(self, *args):
+        self.bytecode.add_step("optional", *args)
+        return self
+
+    def or_(self, *args):
+        self.bytecode.add_step("or", *args)
+        return self
+
+    def order(self, *args):
+        self.bytecode.add_step("order", *args)
+        return self
+
+    def otherV(self, *args):
+        self.bytecode.add_step("otherV", *args)
+        return self
+
+    def out(self, *args):
+        self.bytecode.add_step("out", *args)
+        return self
+
+    def outE(self, *args):
+        self.bytecode.add_step("outE", *args)
+        return self
+
+    def outV(self, *args):
+        self.bytecode.add_step("outV", *args)
+        return self
+
+    def pageRank(self, *args):
+        self.bytecode.add_step("pageRank", *args)
+        return self
+
+    def path(self, *args):
+        self.bytecode.add_step("path", *args)
+        return self
+
+    def peerPressure(self, *args):
+        self.bytecode.add_step("peerPressure", *args)
+        return self
+
+    def profile(self, *args):
+        self.bytecode.add_step("profile", *args)
+        return self
+
+    def program(self, *args):
+        self.bytecode.add_step("program", *args)
+        return self
+
+    def project(self, *args):
+        self.bytecode.add_step("project", *args)
+        return self
+
+    def properties(self, *args):
+        self.bytecode.add_step("properties", *args)
+        return self
+
+    def property(self, *args):
+        self.bytecode.add_step("property", *args)
+        return self
+
+    def propertyMap(self, *args):
+        self.bytecode.add_step("propertyMap", *args)
+        return self
+
+    def range_(self, *args):
+        self.bytecode.add_step("range", *args)
+        return self
+
+    def read(self, *args):
+        self.bytecode.add_step("read", *args)
+        return self
+
+    def repeat(self, *args):
+        self.bytecode.add_step("repeat", *args)
+        return self
+
+    def sack(self, *args):
+        self.bytecode.add_step("sack", *args)
+        return self
+
+    def sample(self, *args):
+        self.bytecode.add_step("sample", *args)
+        return self
+
+    def select(self, *args):
+        self.bytecode.add_step("select", *args)
+        return self
+
+    def shortestPath(self, *args):
+        self.bytecode.add_step("shortestPath", *args)
+        return self
+
+    def sideEffect(self, *args):
+        self.bytecode.add_step("sideEffect", *args)
+        return self
+
+    def simplePath(self, *args):
+        self.bytecode.add_step("simplePath", *args)
+        return self
+
+    def skip(self, *args):
+        self.bytecode.add_step("skip", *args)
+        return self
+
+    def store(self, *args):
+        self.bytecode.add_step("store", *args)
+        return self
+
+    def subgraph(self, *args):
+        self.bytecode.add_step("subgraph", *args)
+        return self
+
+    def sum_(self, *args):
+        self.bytecode.add_step("sum", *args)
+        return self
+
+    def tail(self, *args):
+        self.bytecode.add_step("tail", *args)
+        return self
+
+    def timeLimit(self, *args):
+        self.bytecode.add_step("timeLimit", *args)
+        return self
+
+    def times(self, *args):
+        self.bytecode.add_step("times", *args)
+        return self
+
+    def to(self, *args):
+        self.bytecode.add_step("to", *args)
+        return self
+
+    def toE(self, *args):
+        self.bytecode.add_step("toE", *args)
+        return self
+
+    def toV(self, *args):
+        self.bytecode.add_step("toV", *args)
+        return self
+
+    def tree(self, *args):
+        self.bytecode.add_step("tree", *args)
+        return self
+
+    def unfold(self, *args):
+        self.bytecode.add_step("unfold", *args)
+        return self
+
+    def union(self, *args):
+        self.bytecode.add_step("union", *args)
+        return self
+
+    def until(self, *args):
+        self.bytecode.add_step("until", *args)
+        return self
+
+    def value(self, *args):
+        self.bytecode.add_step("value", *args)
+        return self
+
+    def valueMap(self, *args):
+        self.bytecode.add_step("valueMap", *args)
+        return self
+
+    def values(self, *args):
+        self.bytecode.add_step("values", *args)
+        return self
+
+    def where(self, *args):
+        self.bytecode.add_step("where", *args)
+        return self
+
+    def with_(self, *args):
+        self.bytecode.add_step("with", *args)
+        return self
+
+    def write(self, *args):
+        self.bytecode.add_step("write", *args)
+        return self
+
+    # Deprecated - prefer the underscore suffixed versions e.g filter_()
+
+    def filter(self, *args):
+        self.bytecode.add_step("filter", *args)
+        return self
+
+    def id(self, *args):
+        self.bytecode.add_step("id", *args)
+        return self
+
+    def max(self, *args):
+        self.bytecode.add_step("max", *args)
+        return self
+
+    def min(self, *args):
+        self.bytecode.add_step("min", *args)
+        return self
+
+    def range(self, *args):
+        self.bytecode.add_step("range", *args)
+        return self
+
+    def sum(self, *args):
+        self.bytecode.add_step("sum", *args)
+        return self
+
+
+class MagicType(type):
+
+    def __getattr__(cls, k):
+        if k.startswith('__'):
+            raise AttributeError(
+                'Python magic methods or keys starting with double underscore cannot be used for Gremlin sugar - prefer values(' + k + ')')
+        return __.values(k)
+
+
+class __(object, metaclass=MagicType):
+    graph_traversal = GraphTraversal
+
+    @classmethod
+    def start(cls):
+        return GraphTraversal(None, None, Bytecode())
+
+    @classmethod
+    def __(cls, *args):
+        return __.inject(*args)
+
+    @classmethod
+    def V(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).V(*args)
+
+    @classmethod
+    def addE(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).addE(*args)
+
+    @classmethod
+    def addV(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).addV(*args)
+
+    @classmethod
+    def aggregate(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).aggregate(*args)
+
+    @classmethod
+    def and_(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).and_(*args)
+
+    @classmethod
+    def as_(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).as_(*args)
+
+    @classmethod
+    def barrier(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).barrier(*args)
+
+    @classmethod
+    def both(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).both(*args)
+
+    @classmethod
+    def bothE(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).bothE(*args)
+
+    @classmethod
+    def bothV(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).bothV(*args)
+
+    @classmethod
+    def branch(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).branch(*args)
+
+    @classmethod
+    def cap(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).cap(*args)
+
+    @classmethod
+    def choose(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).choose(*args)
+
+    @classmethod
+    def coalesce(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).coalesce(*args)
+
+    @classmethod
+    def coin(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).coin(*args)
+
+    @classmethod
+    def constant(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).constant(*args)
+
+    @classmethod
+    def count(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).count(*args)
+
+    @classmethod
+    def cyclicPath(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).cyclicPath(*args)
+
+    @classmethod
+    def dedup(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).dedup(*args)
+
+    @classmethod
+    def drop(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).drop(*args)
+
+    @classmethod
+    def elementMap(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).elementMap(*args)
+
+    @classmethod
+    def emit(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).emit(*args)
+
+    @classmethod
+    def filter_(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).filter_(*args)
+
+    @classmethod
+    def flatMap(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).flatMap(*args)
+
+    @classmethod
+    def fold(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).fold(*args)
+
+    @classmethod
+    def group(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).group(*args)
+
+    @classmethod
+    def groupCount(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).groupCount(*args)
+
+    @classmethod
+    def has(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).has(*args)
+
+    @classmethod
+    def hasId(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).hasId(*args)
+
+    @classmethod
+    def hasKey(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).hasKey(*args)
+
+    @classmethod
+    def hasLabel(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).hasLabel(*args)
+
+    @classmethod
+    def hasNot(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).hasNot(*args)
+
+    @classmethod
+    def hasValue(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).hasValue(*args)
+
+    @classmethod
+    def id_(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).id_(*args)
+
+    @classmethod
+    def identity(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).identity(*args)
+
+    @classmethod
+    def inE(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).inE(*args)
+
+    @classmethod
+    def inV(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).inV(*args)
+
+    @classmethod
+    def in_(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).in_(*args)
+
+    @classmethod
+    def index(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).index(*args)
+
+    @classmethod
+    def inject(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).inject(*args)
+
+    @classmethod
+    def is_(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).is_(*args)
+
+    @classmethod
+    def key(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).key(*args)
+
+    @classmethod
+    def label(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).label(*args)
+
+    @classmethod
+    def limit(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).limit(*args)
+
+    @classmethod
+    def local(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).local(*args)
+
+    @classmethod
+    def loops(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).loops(*args)
+
+    @classmethod
+    def map(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).map(*args)
+
+    @classmethod
+    def match(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).match(*args)
+
+    @classmethod
+    def math(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).math(*args)
+
+    @classmethod
+    def max_(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).max_(*args)
+
+    @classmethod
+    def mean(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).mean(*args)
+
+    @classmethod
+    def min_(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).min_(*args)
+
+    @classmethod
+    def not_(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).not_(*args)
+
+    @classmethod
+    def optional(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).optional(*args)
+
+    @classmethod
+    def or_(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).or_(*args)
+
+    @classmethod
+    def order(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).order(*args)
+
+    @classmethod
+    def otherV(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).otherV(*args)
+
+    @classmethod
+    def out(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).out(*args)
+
+    @classmethod
+    def outE(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).outE(*args)
+
+    @classmethod
+    def outV(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).outV(*args)
+
+    @classmethod
+    def path(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).path(*args)
+
+    @classmethod
+    def project(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).project(*args)
+
+    @classmethod
+    def properties(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).properties(*args)
+
+    @classmethod
+    def property(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).property(*args)
+
+    @classmethod
+    def propertyMap(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).propertyMap(*args)
+
+    @classmethod
+    def range_(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).range_(*args)
+
+    @classmethod
+    def repeat(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).repeat(*args)
+
+    @classmethod
+    def sack(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).sack(*args)
+
+    @classmethod
+    def sample(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).sample(*args)
+
+    @classmethod
+    def select(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).select(*args)
+
+    @classmethod
+    def sideEffect(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).sideEffect(*args)
+
+    @classmethod
+    def simplePath(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).simplePath(*args)
+
+    @classmethod
+    def skip(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).skip(*args)
+
+    @classmethod
+    def store(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).store(*args)
+
+    @classmethod
+    def subgraph(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).subgraph(*args)
+
+    @classmethod
+    def sum_(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).sum_(*args)
+
+    @classmethod
+    def tail(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).tail(*args)
+
+    @classmethod
+    def timeLimit(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).timeLimit(*args)
+
+    @classmethod
+    def times(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).times(*args)
+
+    @classmethod
+    def to(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).to(*args)
+
+    @classmethod
+    def toE(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).toE(*args)
+
+    @classmethod
+    def toV(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).toV(*args)
+
+    @classmethod
+    def tree(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).tree(*args)
+
+    @classmethod
+    def unfold(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).unfold(*args)
+
+    @classmethod
+    def union(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).union(*args)
+
+    @classmethod
+    def until(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).until(*args)
+
+    @classmethod
+    def value(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).value(*args)
+
+    @classmethod
+    def valueMap(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).valueMap(*args)
+
+    @classmethod
+    def values(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).values(*args)
+
+    @classmethod
+    def where(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).where(*args)
+
+    # Deprecated - prefer the underscore suffixed versions e.g filter_()
+
+    @classmethod
+    def filter(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).filter_(*args)
+
+    @classmethod
+    def id(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).id_(*args)
+
+    @classmethod
+    def max(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).max_(*args)
+
+    @classmethod
+    def min(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).min_(*args)
+
+    @classmethod
+    def range(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).range_(*args)
+
+    @classmethod
+    def sum(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).sum_(*args)
+
+
+def V(*args):
+    return __.V(*args)
+
+
+def addE(*args):
+    return __.addE(*args)
+
+
+def addV(*args):
+    return __.addV(*args)
+
+
+def aggregate(*args):
+    return __.aggregate(*args)
+
+
+def and_(*args):
+    return __.and_(*args)
+
+
+def as_(*args):
+    return __.as_(*args)
+
+
+def barrier(*args):
+    return __.barrier(*args)
+
+
+def both(*args):
+    return __.both(*args)
+
+
+def bothE(*args):
+    return __.bothE(*args)
+
+
+def bothV(*args):
+    return __.bothV(*args)
+
+
+def branch(*args):
+    return __.branch(*args)
+
+
+def cap(*args):
+    return __.cap(*args)
+
+
+def choose(*args):
+    return __.choose(*args)
+
+
+def coalesce(*args):
+    return __.coalesce(*args)
+
+
+def coin(*args):
+    return __.coin(*args)
+
+
+def constant(*args):
+    return __.constant(*args)
+
+
+def count(*args):
+    return __.count(*args)
+
+
+def cyclicPath(*args):
+    return __.cyclicPath(*args)
+
+
+def dedup(*args):
+    return __.dedup(*args)
+
+
+def drop(*args):
+    return __.drop(*args)
+
+
+def elementMap(*args):
+    return __.elementMap(*args)
+
+
+def emit(*args):
+    return __.emit(*args)
+
+
+def filter_(*args):
+    return __.filter_(*args)
+
+
+def flatMap(*args):
+    return __.flatMap(*args)
+
+
+def fold(*args):
+    return __.fold(*args)
+
+
+def group(*args):
+    return __.group(*args)
+
+
+def groupCount(*args):
+    return __.groupCount(*args)
+
+
+def has(*args):
+    return __.has(*args)
+
+
+def hasId(*args):
+    return __.hasId(*args)
+
+
+def hasKey(*args):
+    return __.hasKey(*args)
+
+
+def hasLabel(*args):
+    return __.hasLabel(*args)
+
+
+def hasNot(*args):
+    return __.hasNot(*args)
+
+
+def hasValue(*args):
+    return __.hasValue(*args)
+
+
+def id_(*args):
+    return __.id_(*args)
+
+
+def identity(*args):
+    return __.identity(*args)
+
+
+def inE(*args):
+    return __.inE(*args)
+
+
+def inV(*args):
+    return __.inV(*args)
+
+
+def in_(*args):
+    return __.in_(*args)
+
+
+def index(*args):
+    return __.index(*args)
+
+
+def inject(*args):
+    return __.inject(*args)
+
+
+def is_(*args):
+    return __.is_(*args)
+
+
+def key(*args):
+    return __.key(*args)
+
+
+def label(*args):
+    return __.label(*args)
+
+
+def limit(*args):
+    return __.limit(*args)
+
+
+def local(*args):
+    return __.local(*args)
+
+
+def loops(*args):
+    return __.loops(*args)
+
+
+def map(*args):
+    return __.map(*args)
+
+
+def match(*args):
+    return __.match(*args)
+
+
+def math(*args):
+    return __.math(*args)
+
+
+def max_(*args):
+    return __.max_(*args)
+
+
+def mean(*args):
+    return __.mean(*args)
+
+
+def min_(*args):
+    return __.min_(*args)
+
+
+def not_(*args):
+    return __.not_(*args)
+
+
+def optional(*args):
+    return __.optional(*args)
+
+
+def or_(*args):
+    return __.or_(*args)
+
+
+def order(*args):
+    return __.order(*args)
+
+
+def otherV(*args):
+    return __.otherV(*args)
+
+
+def out(*args):
+    return __.out(*args)
+
+
+def outE(*args):
+    return __.outE(*args)
+
+
+def outV(*args):
+    return __.outV(*args)
+
+
+def path(*args):
+    return __.path(*args)
+
+
+def project(*args):
+    return __.project(*args)
+
+
+def properties(*args):
+    return __.properties(*args)
+
+
+def property(*args):
+    return __.property(*args)
+
+
+def propertyMap(*args):
+    return __.propertyMap(*args)
+
+
+def range_(*args):
+    return __.range_(*args)
+
+
+def repeat(*args):
+    return __.repeat(*args)
+
+
+def sack(*args):
+    return __.sack(*args)
+
+
+def sample(*args):
+    return __.sample(*args)
+
+
+def select(*args):
+    return __.select(*args)
+
+
+def sideEffect(*args):
+    return __.sideEffect(*args)
+
+
+def simplePath(*args):
+    return __.simplePath(*args)
+
+
+def skip(*args):
+    return __.skip(*args)
+
+
+def store(*args):
+    return __.store(*args)
+
+
+def subgraph(*args):
+    return __.subgraph(*args)
+
+
+def sum_(*args):
+    return __.sum_(*args)
+
+
+def tail(*args):
+    return __.tail(*args)
+
+
+def timeLimit(*args):
+    return __.timeLimit(*args)
+
+
+def times(*args):
+    return __.times(*args)
+
+
+def to(*args):
+    return __.to(*args)
+
+
+def toE(*args):
+    return __.toE(*args)
+
+
+def toV(*args):
+    return __.toV(*args)
+
+
+def tree(*args):
+    return __.tree(*args)
+
+
+def unfold(*args):
+    return __.unfold(*args)
+
+
+def union(*args):
+    return __.union(*args)
+
+
+def until(*args):
+    return __.until(*args)
+
+
+def value(*args):
+    return __.value(*args)
+
+
+def valueMap(*args):
+    return __.valueMap(*args)
+
+
+def values(*args):
+    return __.values(*args)
+
+
+def where(*args):
+    return __.where(*args)
+
+
+# Deprecated - prefer the underscore suffixed versions e.g filter_()
+
+def filter(*args):
+    return __.filter_(*args)
+
+
+def id(*args):
+    return __.id_(*args)
+
+
+def max(*args):
+    return __.max_(*args)
+
+
+def min(*args):
+    return __.min_(*args)
+
+
+def range(*args):
+    return __.range_(*args)
+
+
+def sum(*args):
+    return __.sum_(*args)
+
+
+statics.add_static('V', V)
+
+statics.add_static('addE', addE)
+
+statics.add_static('addV', addV)
+
+statics.add_static('aggregate', aggregate)
+
+statics.add_static('and_', and_)
+
+statics.add_static('as_', as_)
+
+statics.add_static('barrier', barrier)
+
+statics.add_static('both', both)
+
+statics.add_static('bothE', bothE)
+
+statics.add_static('bothV', bothV)
+
+statics.add_static('branch', branch)
+
+statics.add_static('cap', cap)
+
+statics.add_static('choose', choose)
+
+statics.add_static('coalesce', coalesce)
+
+statics.add_static('coin', coin)
+
+statics.add_static('constant', constant)
+
+statics.add_static('count', count)
+
+statics.add_static('cyclicPath', cyclicPath)
+
+statics.add_static('dedup', dedup)
+
+statics.add_static('drop', drop)
+
+statics.add_static('elementMap', elementMap)
+
+statics.add_static('emit', emit)
+
+statics.add_static('filter_', filter_)
+
+statics.add_static('flatMap', flatMap)
+
+statics.add_static('fold', fold)
+
+statics.add_static('group', group)
+
+statics.add_static('groupCount', groupCount)
+
+statics.add_static('has', has)
+
+statics.add_static('hasId', hasId)
+
+statics.add_static('hasKey', hasKey)
+
+statics.add_static('hasLabel', hasLabel)
+
+statics.add_static('hasNot', hasNot)
+
+statics.add_static('hasValue', hasValue)
+
+statics.add_static('id_', id_)
+
+statics.add_static('identity', identity)
+
+statics.add_static('inE', inE)
+
+statics.add_static('inV', inV)
+
+statics.add_static('in_', in_)
+
+statics.add_static('index', index)
+
+statics.add_static('inject', inject)
+
+statics.add_static('is_', is_)
+
+statics.add_static('key', key)
+
+statics.add_static('label', label)
+
+statics.add_static('limit', limit)
+
+statics.add_static('local', local)
+
+statics.add_static('loops', loops)
+
+statics.add_static('map', map)
+
+statics.add_static('match', match)
+
+statics.add_static('math', math)
+
+statics.add_static('max_', max_)
+
+statics.add_static('mean', mean)
+
+statics.add_static('min_', min_)
+
+statics.add_static('not_', not_)
+
+statics.add_static('optional', optional)
+
+statics.add_static('or_', or_)
+
+statics.add_static('order', order)
+
+statics.add_static('otherV', otherV)
+
+statics.add_static('out', out)
+
+statics.add_static('outE', outE)
+
+statics.add_static('outV', outV)
+
+statics.add_static('path', path)
+
+statics.add_static('project', project)
+
+statics.add_static('properties', properties)
+
+statics.add_static('property', property)
+
+statics.add_static('propertyMap', propertyMap)
+
+statics.add_static('range_', range_)
+
+statics.add_static('repeat', repeat)
+
+statics.add_static('sack', sack)
+
+statics.add_static('sample', sample)
+
+statics.add_static('select', select)
+
+statics.add_static('sideEffect', sideEffect)
+
+statics.add_static('simplePath', simplePath)
+
+statics.add_static('skip', skip)
+
+statics.add_static('store', store)
+
+statics.add_static('subgraph', subgraph)
+
+statics.add_static('sum_', sum_)
+
+statics.add_static('tail', tail)
+
+statics.add_static('timeLimit', timeLimit)
+
+statics.add_static('times', times)
+
+statics.add_static('to', to)
+
+statics.add_static('toE', toE)
+
+statics.add_static('toV', toV)
+
+statics.add_static('tree', tree)
+
+statics.add_static('unfold', unfold)
+
+statics.add_static('union', union)
+
+statics.add_static('until', until)
+
+statics.add_static('value', value)
+
+statics.add_static('valueMap', valueMap)
+
+statics.add_static('values', values)
+
+statics.add_static('where', where)
+
+
+# Deprecated - prefer the underscore suffixed versions e.g filter_()
+
+statics.add_static('filter', filter)
+statics.add_static('id', id)
+statics.add_static('max', max)
+statics.add_static('min', min)
+statics.add_static('range', range)
+statics.add_static('sum', sum)
diff --git a/gremlin-python/src/main/python/gremlin_python/process/strategies.py b/gremlin-python/src/main/python/gremlin_python/process/strategies.py
new file mode 100644
index 0000000..86fc3f8
--- /dev/null
+++ b/gremlin-python/src/main/python/gremlin_python/process/strategies.py
@@ -0,0 +1,232 @@
+#
+# 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.
+#
+
+__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
+
+from gremlin_python.process.traversal import TraversalStrategy
+
+base_namespace = 'org.apache.tinkerpop.gremlin.process.traversal.strategy.'
+decoration_namespace = base_namespace + 'decoration.'
+finalization_namespace = base_namespace + 'finalization.'
+optimization_namespace = base_namespace + 'optimization.'
+verification_namespace = base_namespace + 'verification.'
+computer_decoration_namespace = 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.'
+
+#########################
+# DECORATION STRATEGIES #
+#########################
+
+
+class ConnectiveStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self, fqcn=decoration_namespace + 'ConnectiveStrategy')
+
+
+class ElementIdStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self, fqcn=decoration_namespace + 'ElementIdStrategy')
+
+
+# EventStrategy doesn't make sense outside JVM traversal machine
+
+class HaltedTraverserStrategy(TraversalStrategy):
+    def __init__(self, halted_traverser_factory=None):
+        TraversalStrategy.__init__(self, fqcn=decoration_namespace + 'HaltedTraverserStrategy')
+        if halted_traverser_factory is not None:
+            self.configuration["haltedTraverserFactory"] = halted_traverser_factory
+
+
+class OptionsStrategy(TraversalStrategy):
+    def __init__(self, options=None):
+        TraversalStrategy.__init__(self, configuration=options, fqcn=decoration_namespace + 'OptionsStrategy')
+
+
+class PartitionStrategy(TraversalStrategy):
+    def __init__(self, partition_key=None, write_partition=None, read_partitions=None, include_meta_properties=None):
+        TraversalStrategy.__init__(self, fqcn=decoration_namespace + 'PartitionStrategy')
+        if partition_key is not None:
+            self.configuration["partitionKey"] = partition_key
+        if write_partition is not None:
+            self.configuration["writePartition"] = write_partition
+        if read_partitions is not None:
+            self.configuration["readPartitions"] = read_partitions
+        if include_meta_properties is not None:
+            self.configuration["includeMetaProperties"] = include_meta_properties
+
+
+class SeedStrategy(TraversalStrategy):
+    def __init__(self, seed):
+        TraversalStrategy.__init__(self, fqcn="org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SeedStrategy")
+        self.configuration["seed"] = seed
+
+
+class SubgraphStrategy(TraversalStrategy):
+
+    def __init__(self, vertices=None, edges=None, vertex_properties=None):
+        TraversalStrategy.__init__(self, fqcn=decoration_namespace + 'SubgraphStrategy')
+        if vertices is not None:
+            self.configuration["vertices"] = vertices
+        if edges is not None:
+            self.configuration["edges"] = edges
+        if vertex_properties is not None:
+            self.configuration["vertexProperties"] = vertex_properties
+
+
+class VertexProgramStrategy(TraversalStrategy):
+    def __init__(self, graph_computer=None, workers=None, persist=None, result=None, vertices=None, edges=None,
+                 configuration=None):
+        TraversalStrategy.__init__(self, fqcn=computer_decoration_namespace + 'VertexProgramStrategy')
+        if graph_computer is not None:
+            self.configuration["graphComputer"] = graph_computer
+        if workers is not None:
+            self.configuration["workers"] = workers
+        if persist is not None:
+            self.configuration["persist"] = persist
+        if result is not None:
+            self.configuration["result"] = result
+        if vertices is not None:
+            self.configuration["vertices"] = vertices
+        if edges is not None:
+            self.configuration["edges"] = edges
+        if configuration is not None:
+            self.configuration.update(configuration)
+
+
+###########################
+# FINALIZATION STRATEGIES #
+###########################
+
+class MatchAlgorithmStrategy(TraversalStrategy):
+    def __init__(self, match_algorithm=None):
+        TraversalStrategy.__init__(self, fqcn=finalization_namespace + 'MatchAlgorithmStrategy')
+        if match_algorithm is not None:
+            self.configuration["matchAlgorithm"] = match_algorithm
+
+
+###########################
+# OPTIMIZATION STRATEGIES #
+###########################
+
+class AdjacentToIncidentStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'AdjacentToIncidentStrategy')
+
+
+class ByModulatorOptimizationStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self, fqcn="org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.CountStrategy")
+
+
+class CountStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self, fqcn="org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.ByModulatorOptimizationStrategy")
+
+
+class FilterRankingStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'FilterRankingStrategy')
+
+
+class IdentityRemovalStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'IdentityRemovalStrategy')
+
+
+class IncidentToAdjacentStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'IncidentToAdjacentStrategy')
+
+
+class InlineFilterStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'InlineFilterStrategy')
+
+
+class LazyBarrierStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'LazyBarrierStrategy')
+
+
+class MatchPredicateStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'MatchPredicateStrategy')
+
+
+class OrderLimitStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'OrderLimitStrategy')
+
+
+class PathProcessorStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'PathProcessorStrategy')
+
+
+class PathRetractionStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'PathRetractionStrategy')
+
+
+class CountStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'CountStrategy')
+
+
+class RepeatUnrollStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'RepeatUnrollStrategy')
+
+
+class GraphFilterStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'GraphFilterStrategy')
+
+
+
+class EarlyLimitStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'EarlyLimitStrategy')
+
+###########################
+# VERIFICATION STRATEGIES #
+###########################
+
+
+class LambdaRestrictionStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self, fqcn=verification_namespace + 'LambdaRestrictionStrategy')
+
+class ReadOnlyStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self, fqcn=verification_namespace + 'ReadOnlyStrategy')
+
+
+class EdgeLabelVerificationStrategy(TraversalStrategy):
+    def __init__(self, log_warning=False, throw_exception=False):
+        TraversalStrategy.__init__(self, fqcn=verification_namespace + 'EdgeLabelVerificationStrategy')
+        self.configuration["logWarning"] = log_warning
+        self.configuration["throwException"] = throw_exception
+
+
+class ReservedKeysVerificationStrategy(TraversalStrategy):
+    def __init__(self, log_warning=False, throw_exception=False, keys=["id", "label"]):
+        TraversalStrategy.__init__(self, fqcn=verification_namespace + 'ReservedKeysVerificationStrategy')
+        self.configuration["logWarning"] = log_warning
+        self.configuration["throwException"] = throw_exception
+        self.configuration["keys"] = keys
diff --git a/gremlin-python/src/main/python/gremlin_python/process/translator.py b/gremlin-python/src/main/python/gremlin_python/process/translator.py
new file mode 100755
index 0000000..7421e86
--- /dev/null
+++ b/gremlin-python/src/main/python/gremlin_python/process/translator.py
@@ -0,0 +1,171 @@
+#
+# 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.
+#
+
+"""
+Class that can turn traversals back into Gremlin Groovy format text queries.
+Those queries can then be run in the Gremlin console or using the GLV submit(<String>) API or
+sent to any TinkerPop compliant HTTP endpoint.
+"""
+__author__ = 'Kelvin R. Lawrence (gfxman)'
+
+from gremlin_python.process.graph_traversal import __
+from gremlin_python.process.anonymous_traversal import traversal
+from gremlin_python.process.traversal import *
+from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection
+from gremlin_python.process.strategies import *
+from datetime import datetime
+
+
+class Translator:
+    """
+    Turn a bytecode object back into a textual query (Gremlin Groovy script).
+    """
+
+    # Dictionary used to reverse-map token IDs to strings
+    options = {
+      WithOptions.tokens: 'tokens',
+      WithOptions.none: 'none',
+      WithOptions.ids:'ids',
+      WithOptions.labels: 'labels',
+      WithOptions.keys: 'keys',
+      WithOptions.values: 'values',
+      WithOptions.all: 'all',
+      WithOptions.indexer: 'indexer',
+      WithOptions.list: 'list',
+      WithOptions.map: 'map'                           
+    }
+
+    def __init__(self, traversal_source=None):
+        self.traversal_source = traversal_source
+
+    def get_traversal_source(self):
+        return self.traversal_source
+
+    def get_target_language(self):
+        return "gremlin-groovy"
+
+    def of(self,traversal_source):
+        self.traversal_source = traversal_source
+        return self
+
+    # Do any needed special processing for the representation
+    # of strings and dates.
+    def fixup(self, v):
+        if type(v) == str:
+            return f'\'{v}\''
+        elif type(v) == datetime:
+            return self.process_date(v)
+        else:
+            return str(v)
+    
+    # Turn a Python datetime into the equivalent new Date(...)
+    def process_date(self, date):
+        y = date.year - 1900
+        mo = date.month
+        d = date.day
+        h = date.hour
+        mi = date.minute
+        s = date.second
+        return f'new Date({y},{mo},{d},{h},{mi},{s})'
+
+    # Do special processing needed to format predicates that come in
+    # such as "gt(a)" correctly.
+    def process_predicate(self, p):
+        res = str(p).split('(')[0] + '('
+
+        if type(p.value) == list:
+            res += '['
+            for v in p.value:
+                res += self.fixup(v) + ','
+            res = res[0:-1] + ']'
+        else:
+            res += self.fixup(p.value)
+            if p.other is not None:
+                res+= ',' + self.fixup(p.other)
+        res += ')'
+        return res
+
+    # Special processing to handle strategies
+    def process_strategy(self, s):
+        c = 0
+        res = f'new {str(s)}('
+        for key in s.configuration:
+            res += ',' if c > 0 else ''
+            res += key + ':'
+            val = s.configuration[key]
+            if isinstance(val, Traversal):
+                res += self.translate(val.bytecode,child=True)
+            else:
+                res += self.fixup(val)
+            c += 1
+        res += ')'
+        return res
+        pass
+
+    # Main driver of the translation. Different parts of
+    # a Traversal are handled appropriately.
+    def do_translation(self, step):
+        script = ''
+        params = step[1:]
+        script += '.' + step[0] + '('
+        if len(params) > 0:
+            c = 0
+            with_opts = False
+            for p in params:
+                script += ',' if c > 0 else ''
+                if with_opts:
+                  script += f'WithOptions.{self.options[p]}'
+                elif type(p) == Bytecode:
+                    script += self.translate(p, True)
+                elif type(p) == P:
+                    script += self.process_predicate(p)
+                elif type(p) in [Cardinality, Pop]:
+                    tmp = str(p)
+                    script += tmp[0:-1] if tmp.endswith('_') else tmp 
+                elif type(p) in [ReadOnlyStrategy, SubgraphStrategy, VertexProgramStrategy,
+                                 OptionsStrategy, PartitionStrategy]:
+                    script += self.process_strategy(p)
+                elif type(p) == datetime:
+                    script += self.process_date(p)
+                elif p == WithOptions.tokens:
+                    script += 'WithOptions.tokens'
+                    with_opts = True
+                elif type(p) == str:
+                    script += f'\'{p}\''
+                else:
+                    script += str(p)
+                c += 1
+        script += ')'
+        return script
+
+    # Translation starts here. There are two main parts to a 
+    # traversal. Source instructions such as "withSideEffect"
+    # and "withStrategies", and step instructions such as 
+    # "addV" and "repeat". If child is True we will generate
+    # anonymous traversal style syntax.
+    def translate(self, bytecode, child=False):
+        script = '__' if child else self.traversal_source
+        
+        for step in bytecode.source_instructions:
+            script += self.do_translation(step)
+
+        for step in bytecode.step_instructions:
+            script += self.do_translation(step)
+       
+        return script
diff --git a/gremlin-python/src/main/python/gremlin_python/process/traversal.py b/gremlin-python/src/main/python/gremlin_python/process/traversal.py
new file mode 100644
index 0000000..3a850ea
--- /dev/null
+++ b/gremlin-python/src/main/python/gremlin_python/process/traversal.py
@@ -0,0 +1,709 @@
+#
+# 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.
+#
+
+import copy
+from aenum import Enum
+from .. import statics
+from ..statics import long
+
+class Traversal(object):
+    def __init__(self, graph, traversal_strategies, bytecode):
+        self.graph = graph
+        self.traversal_strategies = traversal_strategies
+        self.bytecode = bytecode
+        self.traversers = None
+        self.last_traverser = None
+
+    def __repr__(self):
+        return str(self.bytecode)
+
+    def __eq__(self, other):
+        if isinstance(other, self.__class__):
+            return self.bytecode == other.bytecode
+        else:
+            return False
+
+    def __iter__(self):
+        return self
+
+    def __next__(self):
+        if self.traversers is None:
+            self.traversal_strategies.apply_strategies(self)
+        if self.last_traverser is None:
+            self.last_traverser = next(self.traversers)
+        object = self.last_traverser.object
+        self.last_traverser.bulk = self.last_traverser.bulk - 1
+        if self.last_traverser.bulk <= 0:
+            self.last_traverser = None
+        return object
+
+    def toList(self):
+        return list(iter(self))
+
+    def toSet(self):
+        return set(iter(self))
+
+    def iterate(self):
+        self.bytecode.add_step("none")
+        while True:
+            try: self.nextTraverser()
+            except StopIteration: return self
+
+    def nextTraverser(self):
+        if self.traversers is None:
+            self.traversal_strategies.apply_strategies(self)
+        if self.last_traverser is None:
+            return next(self.traversers)
+        else:
+            temp = self.last_traverser
+            self.last_traverser = None
+            return temp
+
+    def hasNext(self):
+        if self.traversers is None:
+            self.traversal_strategies.apply_strategies(self)
+        if self.last_traverser is None:
+            try: self.last_traverser = next(self.traversers)
+            except StopIteration: return False
+        return not(self.last_traverser is None) and self.last_traverser.bulk > 0
+
+    def next(self, amount=None):
+        if amount is None:
+            return self.__next__()
+        else:
+            count = 0
+            tempList = []
+            while count < amount:
+                count = count + 1
+                try: temp = self.__next__()
+                except StopIteration: return tempList
+                tempList.append(temp)
+            return tempList
+
+    def promise(self, cb=None):
+        self.traversal_strategies.apply_async_strategies(self)
+        future_traversal = self.remote_results
+        future = type(future_traversal)()
+        def process(f):
+            try:
+                traversal = f.result()
+            except Exception as e:
+                future.set_exception(e)
+            else:
+                self.traversers = iter(traversal.traversers)
+                if cb:
+                    try:
+                        result = cb(self)
+                    except Exception as e:
+                        future.set_exception(e)
+                    else:
+                        future.set_result(result)
+                else:
+                    future.set_result(self)
+        future_traversal.add_done_callback(process)
+        return future
+
+
+Barrier = Enum('Barrier', ' normSack')
+
+statics.add_static('normSack', Barrier.normSack)
+
+Cardinality = Enum('Cardinality', ' list_ set_ single')
+
+statics.add_static('single', Cardinality.single)
+statics.add_static('list_', Cardinality.list_)
+statics.add_static('set_', Cardinality.set_)
+
+Column = Enum('Column', ' keys values')
+
+statics.add_static('keys', Column.keys)
+statics.add_static('values', Column.values)
+
+Direction = Enum('Direction', ' BOTH IN OUT')
+
+statics.add_static('OUT', Direction.OUT)
+statics.add_static('IN', Direction.IN)
+statics.add_static('BOTH', Direction.BOTH)
+
+GraphSONVersion = Enum('GraphSONVersion', ' V1_0 V2_0 V3_0')
+
+statics.add_static('V1_0', GraphSONVersion.V1_0)
+statics.add_static('V2_0', GraphSONVersion.V2_0)
+statics.add_static('V3_0', GraphSONVersion.V3_0)
+
+GryoVersion = Enum('GryoVersion', ' V1_0 V3_0')
+
+statics.add_static('V1_0', GryoVersion.V1_0)
+statics.add_static('V3_0', GryoVersion.V3_0)
+
+Order = Enum('Order', ' asc desc shuffle')
+
+statics.add_static('shuffle', Order.shuffle)
+statics.add_static('asc', Order.asc)
+statics.add_static('desc', Order.desc)
+
+Pick = Enum('Pick', ' any none')
+
+statics.add_static('any', Pick.any)
+statics.add_static('none', Pick.none)
+
+Pop = Enum('Pop', ' all_ first last mixed')
+
+statics.add_static('first', Pop.first)
+statics.add_static('last', Pop.last)
+statics.add_static('all_', Pop.all_)
+statics.add_static('mixed', Pop.mixed)
+
+Scope = Enum('Scope', ' global_ local')
+
+statics.add_static('global_', Scope.global_)
+statics.add_static('local', Scope.local)
+
+
+T = Enum('T', ' id id_ key label value')
+
+statics.add_static('id', T.id)
+statics.add_static('label', T.label)
+statics.add_static('id_', T.id_)
+statics.add_static('key', T.key)
+statics.add_static('value', T.value)
+
+
+Operator = Enum('Operator', ' addAll and_ assign div max max_ min min_ minus mult or_ sum sum_ sumLong')
+
+statics.add_static('sum_', Operator.sum_)
+statics.add_static('sum', Operator.sum_)
+statics.add_static('minus', Operator.minus)
+statics.add_static('mult', Operator.mult)
+statics.add_static('div', Operator.div)
+statics.add_static('min', Operator.min_)
+statics.add_static('min_', Operator.min_)
+statics.add_static('max_', Operator.max_)
+statics.add_static('assign', Operator.assign)
+statics.add_static('and_', Operator.and_)
+statics.add_static('or_', Operator.or_)
+statics.add_static('addAll', Operator.addAll)
+statics.add_static('sumLong', Operator.sumLong)
+
+
+class P(object):
+    def __init__(self, operator, value, other=None):
+        self.operator = operator
+        self.value = value
+        self.other = other
+
+    @staticmethod
+    def between(*args):
+        return P("between", *args)
+
+    @staticmethod
+    def eq(*args):
+        return P("eq", *args)
+
+    @staticmethod
+    def gt(*args):
+        return P("gt", *args)
+
+    @staticmethod
+    def gte(*args):
+        return P("gte", *args)
+
+    @staticmethod
+    def inside(*args):
+        return P("inside", *args)
+
+    @staticmethod
+    def lt(*args):
+        return P("lt", *args)
+
+    @staticmethod
+    def lte(*args):
+        return P("lte", *args)
+
+    @staticmethod
+    def neq(*args):
+        return P("neq", *args)
+
+    @staticmethod
+    def not_(*args):
+        return P("not", *args)
+
+    @staticmethod
+    def outside(*args):
+        return P("outside", *args)
+
+    @staticmethod
+    def test(*args):
+        return P("test", *args)
+
+    @staticmethod
+    def within(*args):
+        if len(args) == 1 and type(args[0]) == list:
+            return P("within", args[0])
+        else:
+            return P("within", list(args))
+        
+    @staticmethod
+    def without(*args):
+        if len(args) == 1 and type(args[0]) == list:
+            return P("without", args[0])
+        else:
+            return P("without", list(args))
+
+    def and_(self, arg):
+        return P("and", self, arg)
+
+    def or_(self, arg):
+        return P("or", self, arg)
+
+    def __eq__(self, other):
+        return isinstance(other, self.__class__) and self.operator == other.operator and self.value == other.value and self.other == other.other
+
+    def __repr__(self):
+        return self.operator + "(" + str(self.value) + ")" if self.other is None else self.operator + "(" + str(self.value) + "," + str(self.other) + ")"
+
+
+def between(*args):
+    return P.between(*args)
+
+
+def eq(*args):
+    return P.eq(*args)
+
+
+def gt(*args):
+    return P.gt(*args)
+
+
+def gte(*args):
+    return P.gte(*args)
+
+
+def inside(*args):
+    return P.inside(*args)
+
+
+def lt(*args):
+    return P.lt(*args)
+
+
+def lte(*args):
+    return P.lte(*args)
+
+
+def neq(*args):
+    return P.neq(*args)
+
+
+def not_(*args):
+    return P.not_(*args)
+
+
+def outside(*args):
+    return P.outside(*args)
+
+
+def within(*args):
+    return P.within(*args)
+
+
+def without(*args):
+    return P.without(*args)
+
+
+statics.add_static('between', between)
+
+statics.add_static('eq', eq)
+
+statics.add_static('gt', gt)
+
+statics.add_static('gte', gte)
+
+statics.add_static('inside', inside)
+
+statics.add_static('lt', lt)
+
+statics.add_static('lte', lte)
+
+statics.add_static('neq', neq)
+
+statics.add_static('not_', not_)
+
+statics.add_static('outside', outside)
+
+statics.add_static('within', within)
+
+statics.add_static('without', without)
+
+
+class TextP(P):
+    def __init__(self, operator, value, other=None):
+        P.__init__(self, operator, value, other)
+
+    @staticmethod
+    def containing(*args):
+        return TextP("containing", *args)
+
+    @staticmethod
+    def endingWith(*args):
+        return TextP("endingWith", *args)
+
+    @staticmethod
+    def notContaining(*args):
+        return TextP("notContaining", *args)
+
+    @staticmethod
+    def notEndingWith(*args):
+        return TextP("notEndingWith", *args)
+
+    @staticmethod
+    def notStartingWith(*args):
+        return TextP("notStartingWith", *args)
+
+    @staticmethod
+    def startingWith(*args):
+        return TextP("startingWith", *args)
+
+    def __eq__(self, other):
+        return isinstance(other, self.__class__) and self.operator == other.operator and self.value == other.value and self.other == other.other
+
+    def __repr__(self):
+        return self.operator + "(" + str(self.value) + ")" if self.other is None else self.operator + "(" + str(self.value) + "," + str(self.other) + ")"
+
+
+def containing(*args):
+    return TextP.containing(*args)
+
+
+def endingWith(*args):
+    return TextP.endingWith(*args)
+
+
+def notContaining(*args):
+    return TextP.notContaining(*args)
+
+
+def notEndingWith(*args):
+    return TextP.notEndingWith(*args)
+
+
+def notStartingWith(*args):
+    return TextP.notStartingWith(*args)
+
+
+def startingWith(*args):
+    return TextP.startingWith(*args)
+
+
+statics.add_static('containing', containing)
+
+statics.add_static('endingWith', endingWith)
+
+statics.add_static('notContaining', notContaining)
+
+statics.add_static('notEndingWith', notEndingWith)
+
+statics.add_static('notStartingWith', notStartingWith)
+
+statics.add_static('startingWith', startingWith)
+
+
+
+
+'''
+IO
+'''
+
+
+class IO(object):
+
+    graphml = "graphml"
+
+    graphson = "graphson"
+
+    gryo = "gryo"
+
+    reader = "~tinkerpop.io.reader"
+
+    registry = "~tinkerpop.io.registry"
+
+    writer = "~tinkerpop.io.writer"
+
+
+'''
+ConnectedComponent
+'''
+
+
+class ConnectedComponent(object):
+
+    component = "gremlin.connectedComponentVertexProgram.component"
+
+    edges = "~tinkerpop.connectedComponent.edges"
+
+    propertyName = "~tinkerpop.connectedComponent.propertyName"
+
+
+'''
+ShortestPath
+'''
+
+
+class ShortestPath(object):
+
+    distance = "~tinkerpop.shortestPath.distance"
+
+    edges = "~tinkerpop.shortestPath.edges"
+
+    includeEdges = "~tinkerpop.shortestPath.includeEdges"
+
+    maxDistance = "~tinkerpop.shortestPath.maxDistance"
+
+    target = "~tinkerpop.shortestPath.target"
+
+
+'''
+PageRank
+'''
+
+
+class PageRank(object):
+
+    edges = "~tinkerpop.pageRank.edges"
+
+    propertyName = "~tinkerpop.pageRank.propertyName"
+
+    times = "~tinkerpop.pageRank.times"
+
+
+'''
+PeerPressure
+'''
+
+
+class PeerPressure(object):
+
+    edges = "~tinkerpop.peerPressure.edges"
+
+    propertyName = "~tinkerpop.peerPressure.propertyName"
+
+    times = "~tinkerpop.peerPressure.times"
+
+
+'''
+TRAVERSER
+'''
+
+
+class Traverser(object):
+    def __init__(self, object, bulk=None):
+        if bulk is None:
+            bulk = long(1)
+        self.object = object
+        self.bulk = bulk
+
+    def __repr__(self):
+        return str(self.object)
+
+    def __eq__(self, other):
+        return isinstance(other, self.__class__) and self.object == other.object
+
+
+'''
+TRAVERSAL STRATEGIES
+'''
+
+
+class TraversalStrategies(object):
+    global_cache = {}
+
+    def __init__(self, traversal_strategies=None):
+        self.traversal_strategies =             traversal_strategies.traversal_strategies if traversal_strategies is not None else []
+
+    def add_strategies(self, traversal_strategies):
+        self.traversal_strategies = self.traversal_strategies + traversal_strategies
+
+    def apply_strategies(self, traversal):
+        for traversal_strategy in self.traversal_strategies:
+            traversal_strategy.apply(traversal)
+
+    def apply_async_strategies(self, traversal):
+        for traversal_strategy in self.traversal_strategies:
+            traversal_strategy.apply_async(traversal)
+
+    def __repr__(self):
+        return str(self.traversal_strategies)
+
+
+class TraversalStrategy(object):
+    def __init__(self, strategy_name=None, configuration=None, fqcn=None):
+        self.fqcn = fqcn
+        self.strategy_name = type(self).__name__ if strategy_name is None else strategy_name
+        self.configuration = {} if configuration is None else configuration
+
+    def apply(self, traversal):
+        return
+
+    def apply_async(self, traversal):
+        return
+
+    def __eq__(self, other):
+        return isinstance(other, self.__class__)
+
+    def __hash__(self):
+        return hash(self.strategy_name)
+
+    def __repr__(self):
+        return self.strategy_name
+
+
+'''
+BYTECODE
+'''
+
+
+class Bytecode(object):
+    def __init__(self, bytecode=None):
+        self.source_instructions = []
+        self.step_instructions = []
+        self.bindings = {}
+        if bytecode is not None:
+            self.source_instructions = list(bytecode.source_instructions)
+            self.step_instructions = list(bytecode.step_instructions)
+
+    def add_source(self, source_name, *args):
+        instruction = [source_name]
+        for arg in args:
+            instruction.append(self.__convertArgument(arg))
+        self.source_instructions.append(instruction)
+
+    def add_step(self, step_name, *args):
+        instruction = [step_name]
+        for arg in args:
+            instruction.append(self.__convertArgument(arg))
+        self.step_instructions.append(instruction)
+
+    def __eq__(self, other):
+        if isinstance(other, self.__class__):
+            return self.source_instructions == other.source_instructions and self.step_instructions == other.step_instructions
+        else:
+            return False
+
+    def __copy__(self):
+        bb = Bytecode()
+        bb.source_instructions = self.source_instructions
+        bb.step_instructions = self.step_instructions
+        bb.bindings = self.bindings
+        return bb
+
+    def __deepcopy__(self, memo={}):
+        bb = Bytecode()
+        bb.source_instructions = copy.deepcopy(self.source_instructions, memo)
+        bb.step_instructions = copy.deepcopy(self.step_instructions, memo)
+        bb.bindings = copy.deepcopy(self.bindings, memo)
+        return bb
+
+    def __convertArgument(self,arg):
+        if isinstance(arg, Traversal):
+            if arg.graph is not None:
+                raise TypeError("The child traversal of " + arg + " was not spawned anonymously - use the __ class rather than a TraversalSource to construct the child traversal")
+            self.bindings.update(arg.bytecode.bindings)
+            return arg.bytecode
+        elif isinstance(arg, dict):
+            newDict = {}
+            for key in arg:
+                newDict[self.__convertArgument(key)] = self.__convertArgument(arg[key])
+            return newDict
+        elif isinstance(arg, list):
+            newList = []
+            for item in arg:
+                newList.append(self.__convertArgument(item))
+            return newList
+        elif isinstance(arg, set):
+            newSet = set()
+            for item in arg:
+                newSet.add(self.__convertArgument(item))
+            return newSet
+        elif isinstance(arg, Binding):
+            self.bindings[arg.key] = arg.value
+            return Binding(arg.key, self.__convertArgument(arg.value))
+        else:
+            return arg
+
+    def __repr__(self):
+        return (str(self.source_instructions) if len(self.source_instructions) > 0 else "") + \
+               (str(self.step_instructions) if len(self.step_instructions) > 0 else "")
+
+
+'''
+BINDINGS
+'''
+
+
+class Bindings(object):
+
+    @staticmethod
+    def of(key, value):
+        if not isinstance(key, str):
+            raise TypeError("Key must be str")
+        return Binding(key, value)
+
+
+class Binding(object):
+    def __init__(self, key, value):
+        self.key = key
+        self.value = value
+
+    def __eq__(self, other):
+        return isinstance(other, self.__class__) and self.key == other.key and self.value == other.value
+
+    def __hash__(self):
+        return hash(self.key) + hash(self.value)
+
+    def __repr__(self):
+        return "binding[" + self.key + "=" + str(self.value) + "]"
+
+
+'''
+WITH OPTIONS
+'''
+
+
+class WithOptions(object):
+
+    tokens = "~tinkerpop.valueMap.tokens"
+
+    none = 0
+
+    ids = 1
+
+    labels = 2
+
+    keys = 4
+
+    values = 8
+
+    all = 15
+
+    indexer = "~tinkerpop.index.indexer"
+
+    list = 0
+
+    map = 1
+
diff --git a/gremlin-python/src/main/python/gremlin_python/statics.py b/gremlin-python/src/main/python/gremlin_python/statics.py
new file mode 100644
index 0000000..567a7a3
--- /dev/null
+++ b/gremlin-python/src/main/python/gremlin_python/statics.py
@@ -0,0 +1,101 @@
+#
+# 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.
+#
+
+from types import FunctionType
+from aenum import Enum
+
+
+class long(int):
+    pass
+
+
+FloatType = float
+IntType = int
+LongType = long
+TypeType = type
+ListType = list
+DictType = dict
+SetType = set
+ByteBufferType = bytes
+
+
+class timestamp(float):
+    """
+    In Python a timestamp is simply a float. This dummy class (similar to long), allows users to wrap a float
+    in a GLV script to make sure the value is serialized as a Gremlin timestamp.
+    """
+    pass
+
+
+class SingleByte(int):
+    """
+    Provides a way to pass a single byte via Gremlin.
+    """
+    def __new__(cls, b):
+        if -128 <= b < 128:
+            int.__new__(cls, b)
+        else:
+            raise ValueError("value must be between -128 and 127 inclusive")
+
+
+class SingleChar(str):
+    """
+    Provides a way to pass a single character via Gremlin.
+    """
+    def __new__(cls, c):
+        if len(b) == 1:
+            str.__new__(cls, c)
+        else:
+            raise ValueError("string must contain a single character")
+
+
+class GremlinType(object):
+    """
+    Provides a way to represent a "Java class" for Gremlin.
+    """
+    def __init__(self, gremlin_type):
+        self.gremlin_type = gremlin_type
+        
+
+staticMethods = {}
+staticEnums = {}
+default_lambda_language = "gremlin-groovy"
+
+
+def add_static(key, value):
+    if isinstance(value, Enum):
+        staticEnums[key] = value
+    else:
+        staticMethods[key] = value
+
+
+def load_statics(global_dict):
+    for key in staticMethods:
+        global_dict[key] = staticMethods[key]
+    for key in staticEnums:
+        global_dict[key] = staticEnums[key]
+
+
+def unload_statics(global_dict):
+    for key in staticMethods:
+        if key in global_dict:
+            del global_dict[key]
+    for key in staticEnums:
+        if key in global_dict:
+            del global_dict[key]
diff --git a/gremlin-python/src/main/jython/gremlin_python/structure/__init__.py b/gremlin-python/src/main/python/gremlin_python/structure/__init__.py
similarity index 100%
rename from gremlin-python/src/main/jython/gremlin_python/structure/__init__.py
rename to gremlin-python/src/main/python/gremlin_python/structure/__init__.py
diff --git a/gremlin-python/src/main/jython/gremlin_python/structure/graph.py b/gremlin-python/src/main/python/gremlin_python/structure/graph.py
similarity index 100%
rename from gremlin-python/src/main/jython/gremlin_python/structure/graph.py
rename to gremlin-python/src/main/python/gremlin_python/structure/graph.py
diff --git a/gremlin-python/src/main/jython/gremlin_python/structure/io/__init__.py b/gremlin-python/src/main/python/gremlin_python/structure/io/__init__.py
similarity index 100%
rename from gremlin-python/src/main/jython/gremlin_python/structure/io/__init__.py
rename to gremlin-python/src/main/python/gremlin_python/structure/io/__init__.py
diff --git a/gremlin-python/src/main/python/gremlin_python/structure/io/graphbinaryV1.py b/gremlin-python/src/main/python/gremlin_python/structure/io/graphbinaryV1.py
new file mode 100644
index 0000000..a5a258a
--- /dev/null
+++ b/gremlin-python/src/main/python/gremlin_python/structure/io/graphbinaryV1.py
@@ -0,0 +1,1080 @@
+"""
+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.
+"""
+
+import six
+import datetime
+import calendar
+import uuid
+import math
+import io
+import struct
+from collections import OrderedDict
+import logging
+
+from struct import pack, unpack
+from aenum import Enum
+from datetime import timedelta
+from gremlin_python import statics
+from gremlin_python.statics import FloatType, FunctionType, IntType, LongType, TypeType, DictType, ListType, SetType, \
+                                   SingleByte, ByteBufferType, GremlinType, SingleChar
+from gremlin_python.process.traversal import Barrier, Binding, Bytecode, Cardinality, Column, Direction, Operator, \
+                                             Order, Pick, Pop, P, Scope, TextP, Traversal, Traverser, \
+                                             TraversalStrategy, T
+from gremlin_python.process.graph_traversal import GraphTraversal
+from gremlin_python.structure.graph import Graph, Edge, Property, Vertex, VertexProperty, Path
+from gremlin_python.structure.io.util import HashableDict
+
+log = logging.getLogger(__name__)
+
+# When we fall back to a superclass's serializer, we iterate over this map.
+# We want that iteration order to be consistent, so we use an OrderedDict,
+# not a dict.
+_serializers = OrderedDict()
+_deserializers = {}
+
+
+class DataType(Enum):
+    null = 0xfe
+    int = 0x01
+    long = 0x02
+    string = 0x03
+    date = 0x04
+    timestamp = 0x05
+    clazz = 0x06
+    double = 0x07
+    float = 0x08
+    list = 0x09
+    map = 0x0a
+    set = 0x0b
+    uuid = 0x0c
+    edge = 0x0d
+    path = 0x0e
+    property = 0x0f
+    graph = 0x10                  # not supported - no graph object in python yet
+    vertex = 0x11
+    vertexproperty = 0x12
+    barrier = 0x13
+    binding = 0x14
+    bytecode = 0x15
+    cardinality = 0x16
+    column = 0x17
+    direction = 0x18
+    operator = 0x19
+    order = 0x1a
+    pick = 0x1b
+    pop = 0x1c
+    lambda_ = 0x1d
+    p = 0x1e
+    scope = 0x1f
+    t = 0x20
+    traverser = 0x21
+    bigdecimal = 0x22             # todo
+    biginteger = 0x23             # todo
+    byte = 0x24
+    bytebuffer = 0x25
+    short = 0x26                  # todo
+    boolean = 0x27
+    textp = 0x28
+    traversalstrategy = 0x29
+    bulkset = 0x2a
+    tree = 0x2b                   # not supported - no tree object in Python yet
+    metrics = 0x2c
+    traversalmetrics = 0x2d
+    char = 0x80
+    duration = 0x81
+    inetaddress = 0x82            # todo
+    instant = 0x83                # todo
+    localdate = 0x84              # todo
+    localdatetime = 0x85          # todo
+    localtime = 0x86              # todo
+    monthday = 0x87               # todo
+    offsetdatetime = 0x88         # todo
+    offsettime = 0x89             # todo
+    period = 0x8a                 # todo
+    year = 0x8b                   # todo
+    yearmonth = 0x8c              # todo
+    zonedatetime = 0x8d           # todo
+    zoneoffset = 0x8e             # todo
+    custom = 0x00                 # todo
+
+
+NULL_BYTES = [DataType.null.value, 0x01]
+
+
+def _make_packer(format_string):
+    packer = struct.Struct(format_string)
+    pack = packer.pack
+    unpack = lambda s: packer.unpack(s)[0]
+    return pack, unpack
+
+
+int64_pack, int64_unpack = _make_packer('>q')
+int32_pack, int32_unpack = _make_packer('>i')
+int8_pack, int8_unpack = _make_packer('>b')
+uint64_pack, uint64_unpack = _make_packer('>Q')
+uint8_pack, uint8_unpack = _make_packer('>B')
+float_pack, float_unpack = _make_packer('>f')
+double_pack, double_unpack = _make_packer('>d')
+
+
+class GraphBinaryTypeType(type):
+    def __new__(mcs, name, bases, dct):
+        cls = super(GraphBinaryTypeType, mcs).__new__(mcs, name, bases, dct)
+        if not name.startswith('_'):
+            if cls.python_type:
+                _serializers[cls.python_type] = cls
+            if cls.graphbinary_type:
+                _deserializers[cls.graphbinary_type] = cls
+        return cls
+
+
+class GraphBinaryWriter(object):
+    def __init__(self, serializer_map=None):
+        self.serializers = _serializers.copy()
+        if serializer_map:
+            self.serializers.update(serializer_map)
+
+    def writeObject(self, objectData):
+        return self.toDict(objectData)
+
+    def toDict(self, obj, to_extend=None):
+        if to_extend is None:
+            to_extend = bytearray()
+
+        if obj is None:
+            to_extend.extend(NULL_BYTES)
+            return
+
+        try:
+            t = type(obj)
+            return self.serializers[t].dictify(obj, self, to_extend)
+        except KeyError:
+            for key, serializer in self.serializers.items():
+                if isinstance(obj, key):
+                    return serializer.dictify(obj, self, to_extend)
+
+        if isinstance(obj, dict):
+            return dict((self.toDict(k, to_extend), self.toDict(v, to_extend)) for k, v in obj.items())
+        elif isinstance(obj, set):
+            return set([self.toDict(o, to_extend) for o in obj])
+        elif isinstance(obj, list):
+            return [self.toDict(o, to_extend) for o in obj]
+        else:
+            return obj
+
+
+class GraphBinaryReader(object):
+    def __init__(self, deserializer_map=None):
+        self.deserializers = _deserializers.copy()
+        if deserializer_map:
+            self.deserializers.update(deserializer_map)
+
+    def readObject(self, b):
+        if isinstance(b, bytearray):
+            return self.toObject(io.BytesIO(b))
+        elif isinstance(b, io.BufferedIOBase):
+            return self.toObject(b)
+
+    def toObject(self, buff, data_type=None, nullable=True):
+        if data_type is None:
+            bt = uint8_unpack(buff.read(1))
+            if bt == DataType.null.value:
+                if nullable:
+                    buff.read(1)
+                return None
+            return self.deserializers[DataType(bt)].objectify(buff, self, nullable)
+        else:
+            return self.deserializers[data_type].objectify(buff, self, nullable)
+
+
+@six.add_metaclass(GraphBinaryTypeType)
+class _GraphBinaryTypeIO(object):
+    python_type = None
+    graphbinary_type = None
+
+    symbolMap = {"global_": "global", "as_": "as", "in_": "in", "and_": "and",
+                 "or_": "or", "is_": "is", "not_": "not", "from_": "from",
+                 "set_": "set", "list_": "list", "all_": "all", "with_": "with",
+                 "filter_": "filter", "id_": "id", "max_": "max", "min_": "min", "sum_": "sum"}
+
+    @classmethod
+    def prefix_bytes(cls, graphbin_type, as_value=False, nullable=True, to_extend=None):
+        if to_extend is None:
+            to_extend = bytearray()
+
+        if not as_value:
+            to_extend += uint8_pack(graphbin_type.value)
+
+        if nullable:
+            to_extend += int8_pack(0)
+
+        return to_extend
+
+    @classmethod
+    def read_int(cls, buff):
+        return int32_unpack(buff.read(4))
+
+    @classmethod
+    def unmangle_keyword(cls, symbol):
+        return cls.symbolMap.get(symbol, symbol)
+
+    @classmethod
+    def is_null(cls, buff, reader, else_opt, nullable=True):
+        return None if nullable and buff.read(1)[0] == 0x01 else else_opt(buff, reader)
+
+    def dictify(self, obj, writer, to_extend, as_value=False, nullable=True):
+        raise NotImplementedError()
+
+    def objectify(self, d, reader, nullable=True):
+        raise NotImplementedError()
+        
+
+class LongIO(_GraphBinaryTypeIO):
+
+    python_type = LongType
+    graphbinary_type = DataType.long
+    byte_format_pack = int64_pack
+    byte_format_unpack = int64_unpack
+
+    @classmethod
+    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
+        if obj < -9223372036854775808 or obj > 9223372036854775807:
+            raise Exception("TODO: don't forget bigint")
+        else:
+            cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
+            to_extend.extend(cls.byte_format_pack(obj))
+            return to_extend
+
+    @classmethod
+    def objectify(cls, buff, reader, nullable=True):
+            return cls.is_null(buff, reader, lambda b, r: int64_unpack(buff.read(8)), nullable)
+
+
+class IntIO(LongIO):
+
+    python_type = IntType
+    graphbinary_type = DataType.int
+    byte_format_pack = int32_pack
+    byte_format_unpack = int32_unpack
+
+    @classmethod
+    def objectify(cls, buff, reader, nullable=True):
+        return cls.is_null(buff, reader, lambda b, r: cls.read_int(b), nullable)
+
+
+class DateIO(_GraphBinaryTypeIO):
+
+    python_type = datetime.datetime
+    graphbinary_type = DataType.date
+
+    @classmethod
+    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
+        try:
+            timestamp_seconds = calendar.timegm(obj.utctimetuple())
+            pts = timestamp_seconds * 1e3 + getattr(obj, 'microsecond', 0) / 1e3
+        except AttributeError:
+            pts = calendar.timegm(obj.timetuple()) * 1e3
+
+        ts = int(round(pts))
+        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
+        to_extend.extend(int64_pack(ts))
+        return to_extend
+
+    @classmethod
+    def objectify(cls, buff, reader, nullable=True):
+        return cls.is_null(buff, reader,
+                           lambda b, r: datetime.datetime.utcfromtimestamp(int64_unpack(b.read(8)) / 1000.0),
+                           nullable)
+
+
+# Based on current implementation, this class must always be declared before FloatIO.
+# Seems pretty fragile for future maintainers. Maybe look into this.
+class TimestampIO(_GraphBinaryTypeIO):
+    python_type = statics.timestamp
+    graphbinary_type = DataType.timestamp
+
+    @classmethod
+    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
+        # Java timestamp expects milliseconds integer - Have to use int because of legacy Python
+        ts = int(round(obj * 1000))
+        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
+        to_extend.extend(int64_pack(ts))
+        return to_extend
+
+    @classmethod
+    def objectify(cls, buff, reader, nullable=True):
+        # Python timestamp expects seconds
+        return cls.is_null(buff, reader, lambda b, r: statics.timestamp(int64_unpack(b.read(8)) / 1000.0),
+                           nullable)
+    
+
+def _long_bits_to_double(bits):
+    return unpack('d', pack('Q', bits))[0]
+
+
+NAN = _long_bits_to_double(0x7ff8000000000000)
+POSITIVE_INFINITY = _long_bits_to_double(0x7ff0000000000000)
+NEGATIVE_INFINITY = _long_bits_to_double(0xFff0000000000000)
+
+
+class FloatIO(LongIO):
+
+    python_type = FloatType
+    graphbinary_type = DataType.float
+    graphbinary_base_type = DataType.float
+    byte_format_pack = float_pack
+    byte_format_unpack = float_unpack
+
+    @classmethod
+    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
+        if math.isnan(obj):
+            cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
+            to_extend.extend(cls.byte_format_pack(NAN))
+        elif math.isinf(obj) and obj > 0:
+            cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
+            to_extend.extend(cls.byte_format_pack(POSITIVE_INFINITY))
+        elif math.isinf(obj) and obj < 0:
+            cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
+            to_extend.extend(cls.byte_format_pack(NEGATIVE_INFINITY))
+        else:
+            cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
+            to_extend.extend(cls.byte_format_pack(obj))
+
+        return to_extend
+
+    @classmethod
+    def objectify(cls, buff, reader, nullable=True):
+        return cls.is_null(buff, reader, lambda b, r: float_unpack(b.read(4)), nullable)
+
+
+class DoubleIO(FloatIO):
+    """
+    Floats basically just fall through to double serialization.
+    """
+
+    graphbinary_type = DataType.double
+    graphbinary_base_type = DataType.double
+    byte_format_pack = double_pack
+    byte_format_unpack = double_unpack
+
+    @classmethod
+    def objectify(cls, buff, reader, nullable=True):
+        return cls.is_null(buff, reader, lambda b, r: double_unpack(b.read(8)), nullable)
+
+
+class CharIO(_GraphBinaryTypeIO):
+    python_type = SingleChar
+    graphbinary_type = DataType.char
+
+    @classmethod
+    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
+        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
+        to_extend.extend(obj.encode("utf-8"))
+        return to_extend
+
+    @classmethod
+    def objectify(cls, buff, reader, nullable=True):
+        return cls.is_null(buff, reader, cls._read_char, nullable)
+
+    @classmethod
+    def _read_char(cls, b, r):
+        max_bytes = 4
+        x = b.read(1)
+        while max_bytes > 0:
+            max_bytes = max_bytes - 1
+            try:
+                return x.decode("utf-8")
+            except UnicodeDecodeError:
+                x += b.read(1)
+
+
+class StringIO(_GraphBinaryTypeIO):
+
+    python_type = str
+    graphbinary_type = DataType.string
+
+    @classmethod
+    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
+        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
+        str_bytes = obj.encode("utf-8")
+        to_extend += int32_pack(len(str_bytes))
+        to_extend += str_bytes
+        return to_extend
+
+    @classmethod
+    def objectify(cls, buff, reader, nullable=True):
+        return cls.is_null(buff, reader, lambda b, r: b.read(cls.read_int(b)).decode("utf-8"), nullable)
+
+
+class ListIO(_GraphBinaryTypeIO):
+
+    python_type = list
+    graphbinary_type = DataType.list
+
+    @classmethod
+    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
+        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
+        to_extend.extend(int32_pack(len(obj)))
+        for item in obj:
+            writer.toDict(item, to_extend)
+
+        return to_extend
+
+    @classmethod
+    def objectify(cls, buff, reader, nullable=True):
+        return cls.is_null(buff, reader, cls._read_list, nullable)
+
+    @classmethod
+    def _read_list(cls, b, r):
+        size = cls.read_int(b)
+        the_list = []
+        while size > 0:
+            the_list.append(r.readObject(b))
+            size = size - 1
+
+        return the_list
+
+
+class SetDeserializer(ListIO):
+
+    python_type = SetType
+    graphbinary_type = DataType.set
+
+    @classmethod
+    def objectify(cls, buff, reader, nullable=True):
+        return set(ListIO.objectify(buff, reader, nullable))
+
+
+class MapIO(_GraphBinaryTypeIO):
+
+    python_type = DictType
+    graphbinary_type = DataType.map
+
+    @classmethod
+    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
+        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
+
+        to_extend.extend(int32_pack(len(obj)))
+        for k, v in obj.items():
+            writer.toDict(k, to_extend)
+            writer.toDict(v, to_extend)
+
+        return to_extend
+
+    @classmethod
+    def objectify(cls, buff, reader, nullable=True):
+        return cls.is_null(buff, reader, cls._read_map, nullable)
+
+    @classmethod
+    def _read_map(cls, b, r):
+        size = cls.read_int(b)
+        the_dict = {}
+        while size > 0:
+            k = HashableDict.of(r.readObject(b))
+            v = r.readObject(b)
+            the_dict[k] = v
+            size = size - 1
+
+        return the_dict
+
+
+class UuidIO(_GraphBinaryTypeIO):
+
+    python_type = uuid.UUID
+    graphbinary_type = DataType.uuid
+
+    @classmethod
+    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
+        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
+        to_extend.extend(obj.bytes)
+        return to_extend
+
+    @classmethod
+    def objectify(cls, buff, reader, nullable=True):
+        return cls.is_null(buff, reader, lambda b, r: uuid.UUID(bytes=b.read(16)), nullable)
+
+
+class EdgeIO(_GraphBinaryTypeIO):
+
+    python_type = Edge
+    graphbinary_type = DataType.edge
+
+    @classmethod
+    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
+        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
+
+        writer.toDict(obj.id, to_extend)
+        StringIO.dictify(obj.label, writer, to_extend, True, False)
+        writer.toDict(obj.inV.id, to_extend)
+        StringIO.dictify(obj.inV.label, writer, to_extend, True, False)
+        writer.toDict(obj.outV.id, to_extend)
+        StringIO.dictify(obj.outV.label, writer, to_extend, True, False)
+        to_extend.extend(NULL_BYTES)
+        to_extend.extend(NULL_BYTES)
+
+        return to_extend
+
+    @classmethod
+    def objectify(cls, buff, reader, nullable=True):
+        return cls.is_null(buff, reader, cls._read_edge, nullable)
+
+    @classmethod
+    def _read_edge(cls, b, r):
+        edgeid = r.readObject(b)
+        edgelbl = r.toObject(b, DataType.string, False)
+        inv = Vertex(r.readObject(b), r.toObject(b, DataType.string, False))
+        outv = Vertex(r.readObject(b), r.toObject(b, DataType.string, False))
+        edge = Edge(edgeid, outv, edgelbl, inv)
+        b.read(4)
+        return edge
+
+
+class PathIO(_GraphBinaryTypeIO):
+
+    python_type = Path
+    graphbinary_type = DataType.path
+
+    @classmethod
+    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
+        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
+        writer.toDict(obj.labels, to_extend)
+        writer.toDict(obj.objects, to_extend)
+        return to_extend
+
+    @classmethod
+    def objectify(cls, buff, reader, nullable=True):
+        return cls.is_null(buff, reader, lambda b, r: Path(r.readObject(b), r.readObject(b)), nullable)
+
+
+class PropertyIO(_GraphBinaryTypeIO):
+
+    python_type = Property
+    graphbinary_type = DataType.property
+
+    @classmethod
+    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
+        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
+        StringIO.dictify(obj.key, writer, to_extend, True, False)
+        writer.toDict(obj.value, to_extend)
+        to_extend.extend(NULL_BYTES)
+        return to_extend
+
+    @classmethod
+    def objectify(cls, buff, reader, nullable=True):
+        return cls.is_null(buff, reader, cls._read_property, nullable)
+
+    @classmethod
+    def _read_property(cls, b, r):
+        p = Property(r.toObject(b, DataType.string, False), r.readObject(b), None)
+        b.read(2)
+        return p
+
+
+class TinkerGraphIO(_GraphBinaryTypeIO):
+
+    python_type = Graph
+    graphbinary_type = DataType.graph
+
+    @classmethod
+    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
+        raise AttributeError("TinkerGraph serialization is not currently supported by gremlin-python")
+
+    @classmethod
+    def objectify(cls, b, reader, as_value=False):
+        raise AttributeError("TinkerGraph deserialization is not currently supported by gremlin-python")
+
+
+class VertexIO(_GraphBinaryTypeIO):
+
+    python_type = Vertex
+    graphbinary_type = DataType.vertex
+
+    @classmethod
+    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
+        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
+        writer.toDict(obj.id, to_extend)
+        StringIO.dictify(obj.label, writer, to_extend, True, False)
+        to_extend.extend(NULL_BYTES)
+        return to_extend
+
+    @classmethod
+    def objectify(cls, buff, reader, nullable=True):
+        return cls.is_null(buff, reader, cls._read_vertex, nullable)
+
+    @classmethod
+    def _read_vertex(cls, b, r):
+        vertex = Vertex(r.readObject(b), r.toObject(b, DataType.string, False))
+        b.read(2)
+        return vertex
+
+
+class VertexPropertyIO(_GraphBinaryTypeIO):
+
+    python_type = VertexProperty
+    graphbinary_type = DataType.vertexproperty
+
+    @classmethod
+    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
+        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
+        writer.toDict(obj.id, to_extend)
+        StringIO.dictify(obj.label, writer, to_extend, True, False)
+        writer.toDict(obj.value, to_extend)
+        to_extend.extend(NULL_BYTES)
+        to_extend.extend(NULL_BYTES)
+        return to_extend
+
+    @classmethod
+    def objectify(cls, buff, reader, nullable=True):
+        return cls.is_null(buff, reader, cls._read_vertexproperty, nullable)
+
+    @classmethod
+    def _read_vertexproperty(cls, b, r):
+        vp = VertexProperty(r.readObject(b), r.toObject(b, DataType.string, False), r.readObject(b), None)
+        b.read(4)
+        return vp
+
+
+class _EnumIO(_GraphBinaryTypeIO):
+
+    @classmethod
+    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
+        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
+        StringIO.dictify(cls.unmangle_keyword(str(obj.name)), writer, to_extend)
+        return to_extend
+
+    @classmethod
+    def objectify(cls, buff, reader, nullable=True):
+        return cls.is_null(buff, reader, cls._read_enumval, nullable)
+
+    @classmethod
+    def _read_enumval(cls, b, r):
+        enum_name = r.toObject(b)
+        return cls.python_type[enum_name]
+
+
+class BarrierIO(_EnumIO):
+    graphbinary_type = DataType.barrier
+    python_type = Barrier
+
+
+class CardinalityIO(_EnumIO):
+    graphbinary_type = DataType.cardinality
+    python_type = Cardinality
+
+
+class ColumnIO(_EnumIO):
+    graphbinary_type = DataType.column
+    python_type = Column
+
+
+class DirectionIO(_EnumIO):
+    graphbinary_type = DataType.direction
+    python_type = Direction
+
+
+class OperatorIO(_EnumIO):
+    graphbinary_type = DataType.operator
+    python_type = Operator
+
+
+class OrderIO(_EnumIO):
+    graphbinary_type = DataType.order
+    python_type = Order
+
+
+class PickIO(_EnumIO):
+    graphbinary_type = DataType.pick
+    python_type = Pick
+
+
+class PopIO(_EnumIO):
+    graphbinary_type = DataType.pop
+    python_type = Pop
+
+
+class BindingIO(_GraphBinaryTypeIO):
+
+    python_type = Binding
+    graphbinary_type = DataType.binding
+
+    @classmethod
+    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
+        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
+        StringIO.dictify(obj.key, writer, to_extend, True, False)
+        writer.toDict(obj.value, to_extend)
+        return to_extend
+
+    @classmethod
+    def objectify(cls, buff, reader, nullable=True):
+        return cls.is_null(buff, reader, lambda b, r: Binding(r.toObject(b, DataType.string, False),
+                                                              reader.readObject(b)), nullable)
+
+
+class BytecodeIO(_GraphBinaryTypeIO):
+    python_type = Bytecode
+    graphbinary_type = DataType.bytecode
+
+    @classmethod
+    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
+        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
+        bc = obj.bytecode if isinstance(obj, Traversal) else obj
+        to_extend.extend(int32_pack(len(bc.step_instructions)))
+        for inst in bc.step_instructions:
+            inst_name, inst_args = inst[0], inst[1:] if len(inst) > 1 else []
+            StringIO.dictify(inst_name, writer, to_extend, True, False)
+            to_extend.extend(int32_pack(len(inst_args)))
+            for arg in inst_args:
+                writer.toDict(arg, to_extend)
+
+        to_extend.extend(int32_pack(len(bc.source_instructions)))
+        for inst in bc.source_instructions:
+            inst_name, inst_args = inst[0], inst[1:] if len(inst) > 1 else []
+            StringIO.dictify(inst_name, writer, to_extend, True, False)
+            to_extend.extend(int32_pack(len(inst_args)))
+            for arg in inst_args:
+                if isinstance(arg, TypeType):
+                    writer.toDict(GremlinType(arg().fqcn), to_extend)
+                else:
+                    writer.toDict(arg, to_extend)
+        return to_extend
+
+    @classmethod
+    def objectify(cls, buff, reader, nullable=True):
+        return cls.is_null(buff, reader, cls._read_bytecode, nullable)
+
+    @classmethod
+    def _read_bytecode(cls, b, r):
+        bytecode = Bytecode()
+
+        step_count = cls.read_int(b)
+        ix = 0
+        while ix < step_count:
+            inst = [r.toObject(b, DataType.string, False)]
+            inst_ct = cls.read_int(b)
+            iy = 0
+            while iy < inst_ct:
+                inst.append(r.readObject(b))
+                iy += 1
+            bytecode.step_instructions.append(inst)
+            ix += 1
+
+        source_count = cls.read_int(b)
+        ix = 0
+        while ix < source_count:
+            inst = [r.toObject(b, DataType.string, False)]
+            inst_ct = cls.read_int(b)
+            iy = 0
+            while iy < inst_ct:
+                inst.append(r.readObject(b))
+                iy += 1
+            bytecode.source_instructions.append(inst)
+            ix += 1
+
+        return bytecode
+
+
+class TraversalIO(BytecodeIO):
+    python_type = GraphTraversal
+
+
+class LambdaSerializer(_GraphBinaryTypeIO):
+
+    python_type = FunctionType
+    graphbinary_type = DataType.lambda_
+
+    @classmethod
+    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
+        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
+
+        lambda_result = obj()
+        script = lambda_result if isinstance(lambda_result, str) else lambda_result[0]
+        language = statics.default_lambda_language if isinstance(lambda_result, str) else lambda_result[1]
+
+        StringIO.dictify(language, writer, to_extend, True, False)
+
+        script_cleaned = script
+        script_args = -1
+
+        if language == "gremlin-groovy" and "->" in script:
+            # if the user has explicitly added parameters to the groovy closure then we can easily detect one or two
+            # arg lambdas - if we can't detect 1 or 2 then we just go with "unknown"
+            args = script[0:script.find("->")]
+            script_args = 2 if "," in args else 1
+
+        StringIO.dictify(script_cleaned, writer, to_extend, True, False)
+        to_extend.extend(int32_pack(script_args))
+
+        return to_extend
+
+
+class PSerializer(_GraphBinaryTypeIO):
+    graphbinary_type = DataType.p
+    python_type = P
+
+    @classmethod
+    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
+        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
+
+        StringIO.dictify(obj.operator, writer, to_extend, True, False)
+
+        args = []
+        if obj.other is None:
+            if isinstance(obj.value, ListType):
+                args = obj.value
+            else:
+                args.append(obj.value)
+        else:
+            args.append(obj.value)
+            args.append(obj.other)
+
+        to_extend.extend(int32_pack(len(args)))
+        for a in args:
+            writer.toDict(a, to_extend)
+
+        return to_extend
+
+
+class ScopeIO(_EnumIO):
+    graphbinary_type = DataType.scope
+    python_type = Scope
+
+
+class TIO(_EnumIO):
+    graphbinary_type = DataType.t
+    python_type = T
+
+
+class TraverserIO(_GraphBinaryTypeIO):
+    graphbinary_type = DataType.traverser
+    python_type = Traverser
+
+    @classmethod
+    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
+        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
+        to_extend.extend(int64_pack(obj.bulk))
+        writer.toDict(obj.object, to_extend)
+        return to_extend
+
+    @classmethod
+    def objectify(cls, buff, reader, nullable=True):
+        return cls.is_null(buff, reader, cls._read_traverser, nullable)
+
+    @classmethod
+    def _read_traverser(cls, b, r):
+        bulk = int64_unpack(b.read(8))
+        obj = r.readObject(b)
+        return Traverser(obj, bulk=bulk)
+
+
+class ByteIO(_GraphBinaryTypeIO):
+    python_type = SingleByte
+    graphbinary_type = DataType.byte
+
+    @classmethod
+    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
+        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
+        to_extend.extend(int8_pack(obj))
+        return to_extend
+
+    @classmethod
+    def objectify(cls, buff, reader, nullable=True):
+        return cls.is_null(buff, reader,
+                           lambda b, r: int.__new__(SingleByte, int8_unpack(b.read(1))),
+                           nullable)
+
+
+class ByteBufferIO(_GraphBinaryTypeIO):
+    python_type = ByteBufferType
+    graphbinary_type = DataType.bytebuffer
+
+    @classmethod
+    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
+        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
+        to_extend.extend(int32_pack(len(obj)))
+        to_extend.extend(obj)
+        return to_extend
+
+    @classmethod
+    def objectify(cls, buff, reader, nullable=True):
+        return cls.is_null(buff, reader, cls._read_bytebuffer, nullable)
+
+    @classmethod
+    def _read_bytebuffer(cls, b, r):
+        size = cls.read_int(b)
+        return ByteBufferType(b.read(size))
+
+
+class BooleanIO(_GraphBinaryTypeIO):
+    python_type = bool
+    graphbinary_type = DataType.boolean
+
+    @classmethod
+    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
+        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
+        to_extend.extend(int8_pack(0x01 if obj else 0x00))
+        return to_extend
+
+    @classmethod
+    def objectify(cls, buff, reader, nullable=True):
+        return cls.is_null(buff, reader,
+                           lambda b, r: True if int8_unpack(b.read(1)) == 0x01 else False,
+                           nullable)
+
+
+class TextPSerializer(_GraphBinaryTypeIO):
+    graphbinary_type = DataType.textp
+    python_type = TextP
+
+    @classmethod
+    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
+        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
+
+        StringIO.dictify(obj.operator, writer, to_extend, True, False)
+
+        args = []
+        if obj.other is None:
+            if isinstance(obj.value, ListType):
+                args = obj.value
+            else:
+                args.append(obj.value)
+        else:
+            args.append(obj.value)
+            args.append(obj.other)
+
+        to_extend.extend(int32_pack(len(args)))
+        for a in args:
+            writer.toDict(a, to_extend)
+
+        return to_extend
+
+
+class BulkSetDeserializer(_GraphBinaryTypeIO):
+
+    graphbinary_type = DataType.bulkset
+
+    @classmethod
+    def objectify(cls, buff, reader, nullable=True):
+        return cls.is_null(buff, reader, cls._read_bulkset, nullable)
+
+    @classmethod
+    def _read_bulkset(cls, b, r):
+        size = cls.read_int(b)
+        the_list = []
+        while size > 0:
+            itm = r.readObject(b)
+            bulk = int64_unpack(b.read(8))
+            for y in range(bulk):
+                the_list.append(itm)            
+            size = size - 1
+
+        return the_list
+
+
+class MetricsDeserializer(_GraphBinaryTypeIO):
+
+    graphbinary_type = DataType.metrics
+
+    @classmethod
+    def objectify(cls, buff, reader, nullable=True):
+        return cls.is_null(buff, reader, cls._read_metrics, nullable)
+
+    @classmethod
+    def _read_metrics(cls, b, r):
+        metricid = r.toObject(b, DataType.string, False)
+        name = r.toObject(b, DataType.string, False)
+        duration = r.toObject(b, DataType.long, nullable=False)
+        counts = r.toObject(b, DataType.map, nullable=False)
+        annotations = r.toObject(b, DataType.map, nullable=False)
+        metrics = r.toObject(b, DataType.list, nullable=False)
+
+        return {"id": metricid,
+                "name": name,
+                "dur": duration,
+                "counts": counts,
+                "annotations": annotations,
+                "metrics": metrics}
+
+
+class TraversalMetricsDeserializer(_GraphBinaryTypeIO):
+
+    graphbinary_type = DataType.traversalmetrics
+
+    @classmethod
+    def objectify(cls, buff, reader, nullable=True):
+        return cls.is_null(buff, reader, cls._read_traversalmetrics, nullable)
+
+    @classmethod
+    def _read_traversalmetrics(cls, b, r):
+        duration = r.toObject(b, DataType.long, nullable=False)
+        metrics = r.toObject(b, DataType.list, nullable=False)
+
+        return {"dur": duration,
+                "metrics": metrics}
+
+
+class ClassSerializer(_GraphBinaryTypeIO):
+    graphbinary_type = DataType.clazz
+    python_type = GremlinType
+
+    @classmethod
+    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
+        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
+        StringIO.dictify(obj.gremlin_type, writer, to_extend, True, False)
+        return to_extend
+
+
+class TraversalStrategySerializer(_GraphBinaryTypeIO):
+    graphbinary_type = DataType.traversalstrategy
+    python_type = TraversalStrategy
+
+    @classmethod
+    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
+        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
+
+        ClassSerializer.dictify(GremlinType(obj.fqcn), writer, to_extend, True, False)
+        conf = {k: cls._convert(v) for k, v in obj.configuration.items()}
+        MapIO.dictify(conf, writer, to_extend, True, False)
+
+        return to_extend
+
+    @classmethod
+    def _convert(cls, v):
+        return v.bytecode if isinstance(v, Traversal) else v
+
+
+class DurationIO(_GraphBinaryTypeIO):
+    python_type = timedelta
+    graphbinary_type = DataType.duration
+
+    @classmethod
+    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
+        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
+        LongIO.dictify(obj.seconds, writer, to_extend, True, False)
+        IntIO.dictify(obj.microseconds * 1000, writer, to_extend, True, False)
+        return to_extend
+
+    @classmethod
+    def objectify(cls, buff, reader, nullable=True):
+        return cls.is_null(buff, reader, cls._read_duration, nullable)
+    
+    @classmethod
+    def _read_duration(cls, b, r):
+        seconds = r.toObject(b, DataType.long, False)
+        nanos = r.toObject(b, DataType.int, False)
+        return timedelta(seconds=seconds, microseconds=nanos / 1000)
diff --git a/gremlin-python/src/main/python/gremlin_python/structure/io/graphsonV2d0.py b/gremlin-python/src/main/python/gremlin_python/structure/io/graphsonV2d0.py
new file mode 100644
index 0000000..20d186e
--- /dev/null
+++ b/gremlin-python/src/main/python/gremlin_python/structure/io/graphsonV2d0.py
@@ -0,0 +1,632 @@
+#
+# 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.
+#
+
+import calendar
+import datetime
+import json
+import uuid
+import math
+from collections import OrderedDict
+from decimal import *
+from datetime import timedelta
+
+import six
+from aenum import Enum
+from isodate import parse_duration, duration_isoformat
+
+from gremlin_python import statics
+from gremlin_python.statics import FloatType, FunctionType, IntType, LongType, TypeType, SingleByte, ByteBufferType, SingleChar
+from gremlin_python.process.traversal import Binding, Bytecode, P, TextP, Traversal, Traverser, TraversalStrategy
+from gremlin_python.structure.graph import Edge, Property, Vertex, VertexProperty, Path
+
+# When we fall back to a superclass's serializer, we iterate over this map.
+# We want that iteration order to be consistent, so we use an OrderedDict,
+# not a dict.
+_serializers = OrderedDict()
+_deserializers = {}
+
+
+class GraphSONTypeType(type):
+    def __new__(mcs, name, bases, dct):
+        cls = super(GraphSONTypeType, mcs).__new__(mcs, name, bases, dct)
+        if not name.startswith('_'):
+            if cls.python_type:
+                _serializers[cls.python_type] = cls
+            if cls.graphson_type:
+                _deserializers[cls.graphson_type] = cls
+        return cls
+
+
+class GraphSONUtil(object):
+    TYPE_KEY = "@type"
+    VALUE_KEY = "@value"
+
+    @classmethod
+    def typedValue(cls, type_name, value, prefix="g"):
+        out = {cls.TYPE_KEY: cls.formatType(prefix, type_name)}
+        if value is not None:
+            out[cls.VALUE_KEY] = value
+        return out
+
+    @classmethod
+    def formatType(cls, prefix, type_name):
+        return "%s:%s" % (prefix, type_name)
+
+
+# Read/Write classes split to follow precedence of the Java API
+class GraphSONWriter(object):
+    def __init__(self, serializer_map=None):
+        """
+        :param serializer_map: map from Python type to serializer instance implementing `dictify`
+        """
+        self.serializers = _serializers.copy()
+        if serializer_map:
+            self.serializers.update(serializer_map)
+
+    def writeObject(self, objectData):
+        # to JSON
+        return json.dumps(self.toDict(objectData), separators=(',', ':'))
+
+    def toDict(self, obj):
+        """
+        Encodes python objects in GraphSON type-tagged dict values
+        """
+        try:
+            return self.serializers[type(obj)].dictify(obj, self)
+        except KeyError:
+            for key, serializer in self.serializers.items():
+                if isinstance(obj, key):
+                    return serializer.dictify(obj, self)
+
+        # list and map are treated as normal json objs (could be isolated serializers)
+        if isinstance(obj, (list, set)):
+            return [self.toDict(o) for o in obj]
+        elif isinstance(obj, dict):
+            return dict((self.toDict(k), self.toDict(v)) for k, v in obj.items())
+        else:
+            return obj
+
+
+class GraphSONReader(object):
+    def __init__(self, deserializer_map=None):
+        """
+        :param deserializer_map: map from GraphSON type tag to deserializer instance implementing `objectify`
+        """
+        self.deserializers = _deserializers.copy()
+        if deserializer_map:
+            self.deserializers.update(deserializer_map)
+
+    def readObject(self, jsonData):
+        # from JSON
+        return self.toObject(json.loads(jsonData))
+
+    def toObject(self, obj):
+        """
+        Unpacks GraphSON type-tagged dict values into objects mapped in self.deserializers
+        """
+        if isinstance(obj, dict):
+            try:
+                return self.deserializers[obj[GraphSONUtil.TYPE_KEY]].objectify(obj[GraphSONUtil.VALUE_KEY], self)
+            except KeyError:
+                pass
+            # list and map are treated as normal json objs (could be isolated deserializers)
+            return dict((self.toObject(k), self.toObject(v)) for k, v in obj.items())
+        elif isinstance(obj, list):
+            return [self.toObject(o) for o in obj]
+        else:
+            return obj
+
+
+@six.add_metaclass(GraphSONTypeType)
+class _GraphSONTypeIO(object):
+    python_type = None
+    graphson_type = None
+
+    symbolMap = {"global_": "global", "as_": "as", "in_": "in", "and_": "and",
+                 "or_": "or", "is_": "is", "not_": "not", "from_": "from",
+                 "set_": "set", "list_": "list", "all_": "all", "with_": "with",
+                 "filter_": "filter", "id_": "id", "max_": "max", "min_": "min", "sum_": "sum"}
+
+    @classmethod
+    def unmangleKeyword(cls, symbol):
+        return cls.symbolMap.get(symbol, symbol)
+
+    def dictify(self, obj, writer):
+        raise NotImplementedError()
+
+    def objectify(self, d, reader):
+        raise NotImplementedError()
+
+
+class _BytecodeSerializer(_GraphSONTypeIO):
+    @classmethod
+    def _dictify_instructions(cls, instructions, writer):
+        out = []
+        for instruction in instructions:
+            inst = [instruction[0]]
+            inst.extend(writer.toDict(arg) for arg in instruction[1:])
+            out.append(inst)
+        return out
+
+    @classmethod
+    def dictify(cls, bytecode, writer):
+        if isinstance(bytecode, Traversal):
+            bytecode = bytecode.bytecode
+        out = {}
+        if bytecode.source_instructions:
+            out["source"] = cls._dictify_instructions(bytecode.source_instructions, writer)
+        if bytecode.step_instructions:
+            out["step"] = cls._dictify_instructions(bytecode.step_instructions, writer)
+        return GraphSONUtil.typedValue("Bytecode", out)
+
+class TraversalSerializer(_BytecodeSerializer):
+    python_type = Traversal
+
+
+class BytecodeSerializer(_BytecodeSerializer):
+    python_type = Bytecode
+
+
+class VertexSerializer(_GraphSONTypeIO):
+    python_type = Vertex
+    graphson_type = "g:Vertex"
+
+    @classmethod
+    def dictify(cls, vertex, writer):
+        return GraphSONUtil.typedValue("Vertex", {"id": writer.toDict(vertex.id),
+                                                  "label": writer.toDict(vertex.label)})
+
+
+class EdgeSerializer(_GraphSONTypeIO):
+    python_type = Edge
+    graphson_type = "g:Edge"
+
+    @classmethod
+    def dictify(cls, edge, writer):
+        return GraphSONUtil.typedValue("Edge", {"id": writer.toDict(edge.id),
+                                                "outV": writer.toDict(edge.outV.id),
+                                                "outVLabel": writer.toDict(edge.outV.label),
+                                                "label": writer.toDict(edge.label),
+                                                "inV": writer.toDict(edge.inV.id),
+                                                "inVLabel": writer.toDict(edge.inV.label)})
+
+
+class VertexPropertySerializer(_GraphSONTypeIO):
+    python_type = VertexProperty
+    graphson_type = "g:VertexProperty"
+
+    @classmethod
+    def dictify(cls, vertex_property, writer):
+        return GraphSONUtil.typedValue("VertexProperty", {"id": writer.toDict(vertex_property.id),
+                                                          "label": writer.toDict(vertex_property.label),
+                                                          "value": writer.toDict(vertex_property.value),
+                                                          "vertex": writer.toDict(vertex_property.vertex.id)})
+
+
+class PropertySerializer(_GraphSONTypeIO):
+    python_type = Property
+    graphson_type = "g:Property"
+
+    @classmethod
+    def dictify(cls, property, writer):
+        elementDict = writer.toDict(property.element)
+        if elementDict is not None:
+            valueDict = elementDict["@value"]
+            if "outVLabel" in valueDict:
+                del valueDict["outVLabel"]
+            if "inVLabel" in valueDict:
+                del valueDict["inVLabel"]
+            if "properties" in valueDict:
+                del valueDict["properties"]
+            if "value" in valueDict:
+                del valueDict["value"]
+        return GraphSONUtil.typedValue("Property", {"key": writer.toDict(property.key),
+                                                    "value": writer.toDict(property.value),
+                                                    "element": elementDict})
+
+
+class TraversalStrategySerializer(_GraphSONTypeIO):
+    python_type = TraversalStrategy
+
+    @classmethod
+    def dictify(cls, strategy, writer):
+        return GraphSONUtil.typedValue(strategy.strategy_name, writer.toDict(strategy.configuration))
+
+
+class TraverserIO(_GraphSONTypeIO):
+    python_type = Traverser
+    graphson_type = "g:Traverser"
+
+    @classmethod
+    def dictify(cls, traverser, writer):
+        return GraphSONUtil.typedValue("Traverser", {"value": writer.toDict(traverser.object),
+                                                     "bulk": writer.toDict(traverser.bulk)})
+
+    @classmethod
+    def objectify(cls, d, reader):
+        return Traverser(reader.toObject(d["value"]),
+                         reader.toObject(d["bulk"]))
+
+
+class EnumSerializer(_GraphSONTypeIO):
+    python_type = Enum
+
+    @classmethod
+    def dictify(cls, enum, _):
+        return GraphSONUtil.typedValue(cls.unmangleKeyword(type(enum).__name__),
+                                       cls.unmangleKeyword(str(enum.name)))
+
+
+class PSerializer(_GraphSONTypeIO):
+    python_type = P
+
+    @classmethod
+    def dictify(cls, p, writer):
+        out = {"predicate": p.operator,
+               "value": [writer.toDict(p.value), writer.toDict(p.other)] if p.other is not None else
+               writer.toDict(p.value)}
+        return GraphSONUtil.typedValue("P", out)
+
+
+class TextPSerializer(_GraphSONTypeIO):
+    python_type = TextP
+
+    @classmethod
+    def dictify(cls, p, writer):
+        out = {"predicate": p.operator,
+               "value": [writer.toDict(p.value), writer.toDict(p.other)] if p.other is not None else
+               writer.toDict(p.value)}
+        return GraphSONUtil.typedValue("TextP", out)
+
+
+class BindingSerializer(_GraphSONTypeIO):
+    python_type = Binding
+
+    @classmethod
+    def dictify(cls, binding, writer):
+        out = {"key": binding.key,
+               "value": writer.toDict(binding.value)}
+        return GraphSONUtil.typedValue("Binding", out)
+
+
+class LambdaSerializer(_GraphSONTypeIO):
+    python_type = FunctionType
+
+    @classmethod
+    def dictify(cls, lambda_object, writer):
+        lambda_result = lambda_object()
+        script = lambda_result if isinstance(lambda_result, str) else lambda_result[0]
+        language = statics.default_lambda_language if isinstance(lambda_result, str) else lambda_result[1]
+        out = {"script": script,
+               "language": language}
+        if language == "gremlin-groovy" and "->" in script:
+            # if the user has explicitly added parameters to the groovy closure then we can easily detect one or two
+            # arg lambdas - if we can't detect 1 or 2 then we just go with "unknown"
+            args = script[0:script.find("->")]
+            out["arguments"] = 2 if "," in args else 1
+        else:
+            out["arguments"] = -1
+
+        return GraphSONUtil.typedValue("Lambda", out)
+
+
+class TypeSerializer(_GraphSONTypeIO):
+    python_type = TypeType
+
+    @classmethod
+    def dictify(cls, typ, writer):
+        return writer.toDict(typ())
+
+
+class UUIDIO(_GraphSONTypeIO):
+    python_type = uuid.UUID
+    graphson_type = "g:UUID"
+    graphson_base_type = "UUID"
+
+    @classmethod
+    def dictify(cls, obj, writer):
+        return GraphSONUtil.typedValue(cls.graphson_base_type, str(obj))
+
+    @classmethod
+    def objectify(cls, d, reader):
+        return cls.python_type(d)
+
+
+class DateIO(_GraphSONTypeIO):
+    python_type = datetime.datetime
+    graphson_type = "g:Date"
+    graphson_base_type = "Date"
+
+    @classmethod
+    def dictify(cls, obj, writer):
+        try:
+            timestamp_seconds = calendar.timegm(obj.utctimetuple())
+            pts = timestamp_seconds * 1e3 + getattr(obj, 'microsecond', 0) / 1e3
+        except AttributeError:
+            pts = calendar.timegm(obj.timetuple()) * 1e3
+
+        ts = int(round(pts))
+        return GraphSONUtil.typedValue(cls.graphson_base_type, ts)
+
+    @classmethod
+    def objectify(cls, ts, reader):
+        # Python timestamp expects seconds
+        return datetime.datetime.utcfromtimestamp(ts / 1000.0)
+
+
+# Based on current implementation, this class must always be declared before FloatIO.
+# Seems pretty fragile for future maintainers. Maybe look into this.
+class TimestampIO(_GraphSONTypeIO):
+    """A timestamp in Python is type float"""
+    python_type = statics.timestamp
+    graphson_type = "g:Timestamp"
+    graphson_base_type = "Timestamp"
+
+    @classmethod
+    def dictify(cls, obj, writer):
+        # Java timestamp expects milliseconds integer
+        # Have to use int because of legacy Python
+        ts = int(round(obj * 1000))
+        return GraphSONUtil.typedValue(cls.graphson_base_type, ts)
+
+    @classmethod
+    def objectify(cls, ts, reader):
+        # Python timestamp expects seconds
+        return cls.python_type(ts / 1000.0)
+
+
+class _NumberIO(_GraphSONTypeIO):
+    @classmethod
+    def dictify(cls, n, writer):
+        if isinstance(n, bool):  # because isinstance(False, int) and isinstance(True, int)
+            return n
+        return GraphSONUtil.typedValue(cls.graphson_base_type, n)
+
+    @classmethod
+    def objectify(cls, v, _):
+        return cls.python_type(v)
+
+
+class FloatIO(_NumberIO):
+    python_type = FloatType
+    graphson_type = "g:Float"
+    graphson_base_type = "Float"
+
+    @classmethod
+    def dictify(cls, n, writer):
+        if isinstance(n, bool):  # because isinstance(False, int) and isinstance(True, int)
+            return n
+        elif math.isnan(n):
+            return GraphSONUtil.typedValue(cls.graphson_base_type, "NaN")
+        elif math.isinf(n) and n > 0:
+            return GraphSONUtil.typedValue(cls.graphson_base_type, "Infinity")
+        elif math.isinf(n) and n < 0:
+            return GraphSONUtil.typedValue(cls.graphson_base_type, "-Infinity")
+        else:
+            return GraphSONUtil.typedValue(cls.graphson_base_type, n)
+
+    @classmethod
+    def objectify(cls, v, _):
+        if isinstance(v, str):
+            if v == 'NaN':
+                return float('nan')
+            elif v == "Infinity":
+                return float('inf')
+            elif v == "-Infinity":
+                return float('-inf')
+
+        return cls.python_type(v)
+
+
+class BigDecimalIO(_NumberIO):
+    python_type = Decimal
+    graphson_type = "gx:BigDecimal"
+    graphson_base_type = "BigDecimal"
+
+    @classmethod
+    def dictify(cls, n, writer):
+        if isinstance(n, bool):  # because isinstance(False, int) and isinstance(True, int)
+            return n
+        elif math.isnan(n):
+            return GraphSONUtil.typedValue(cls.graphson_base_type, "NaN", "gx")
+        elif math.isinf(n) and n > 0:
+            return GraphSONUtil.typedValue(cls.graphson_base_type, "Infinity", "gx")
+        elif math.isinf(n) and n < 0:
+            return GraphSONUtil.typedValue(cls.graphson_base_type, "-Infinity", "gx")
+        else:
+            return GraphSONUtil.typedValue(cls.graphson_base_type, str(n), "gx")
+
+    @classmethod
+    def objectify(cls, v, _):
+        if isinstance(v, str):
+            if v == 'NaN':
+                return Decimal('nan')
+            elif v == "Infinity":
+                return Decimal('inf')
+            elif v == "-Infinity":
+                return Decimal('-inf')
+
+        return Decimal(v)
+
+
+class DoubleIO(FloatIO):
+    graphson_type = "g:Double"
+    graphson_base_type = "Double"
+
+
+class Int64IO(_NumberIO):
+    python_type = LongType
+    graphson_type = "g:Int64"
+    graphson_base_type = "Int64"
+
+    @classmethod
+    def dictify(cls, n, writer):
+        # if we exceed Java long range then we need a BigInteger
+        if isinstance(n, bool):
+            return n
+        elif n < -9223372036854775808 or n > 9223372036854775807:
+            return GraphSONUtil.typedValue("BigInteger", str(n), "gx")
+        else:
+            return GraphSONUtil.typedValue(cls.graphson_base_type, n)
+
+
+class BigIntegerIO(Int64IO):
+    graphson_type = "gx:BigInteger"
+
+
+class Int32IO(Int64IO):
+    python_type = IntType
+    graphson_type = "g:Int32"
+    graphson_base_type = "Int32"
+
+    @classmethod
+    def dictify(cls, n, writer):
+        # if we exceed Java int range then we need a long
+        if isinstance(n, bool):
+            return n
+        elif n < -9223372036854775808 or n > 9223372036854775807:
+            return GraphSONUtil.typedValue("BigInteger", str(n), "gx")
+        elif n < -2147483648 or n > 2147483647:
+            return GraphSONUtil.typedValue("Int64", n)
+        else:
+            return GraphSONUtil.typedValue(cls.graphson_base_type, n)
+
+
+class ByteIO(_NumberIO):
+    python_type = SingleByte
+    graphson_type = "gx:Byte"
+    graphson_base_type = "Byte"
+
+    @classmethod
+    def dictify(cls, n, writer):
+        if isinstance(n, bool):  # because isinstance(False, int) and isinstance(True, int)
+            return n
+        return GraphSONUtil.typedValue(cls.graphson_base_type, n, "gx")
+
+    @classmethod
+    def objectify(cls, v, _):
+        return int.__new__(SingleByte, v)
+
+
+class ByteBufferIO(_GraphSONTypeIO):
+    python_type = ByteBufferType
+    graphson_type = "gx:ByteBuffer"
+    graphson_base_type = "ByteBuffer"
+
+    @classmethod
+    def dictify(cls, n, writer):
+        return GraphSONUtil.typedValue(cls.graphson_base_type, "".join(chr(x) for x in n), "gx")
+
+    @classmethod
+    def objectify(cls, v, _):
+        return cls.python_type(v, "utf8")
+
+
+class CharIO(_GraphSONTypeIO):
+    python_type = SingleChar
+    graphson_type = "gx:Char"
+    graphson_base_type = "Char"
+
+    @classmethod
+    def dictify(cls, n, writer):
+        return GraphSONUtil.typedValue(cls.graphson_base_type, n, "gx")
+
+    @classmethod
+    def objectify(cls, v, _):
+        return str.__new__(SingleChar, v)
+
+
+class DurationIO(_GraphSONTypeIO):
+    python_type = timedelta
+    graphson_type = "gx:Duration"
+    graphson_base_type = "Duration"
+
+    @classmethod
+    def dictify(cls, n, writer):
+        return GraphSONUtil.typedValue(cls.graphson_base_type, duration_isoformat(n), "gx")
+
+    @classmethod
+    def objectify(cls, v, _):
+        return parse_duration(v)
+
+
+class VertexDeserializer(_GraphSONTypeIO):
+    graphson_type = "g:Vertex"
+
+    @classmethod
+    def objectify(cls, d, reader):
+        return Vertex(reader.toObject(d["id"]), d.get("label", "vertex"))
+
+
+class EdgeDeserializer(_GraphSONTypeIO):
+    graphson_type = "g:Edge"
+
+    @classmethod
+    def objectify(cls, d, reader):
+        return Edge(reader.toObject(d["id"]),
+                    Vertex(reader.toObject(d["outV"]), d.get("outVLabel", "vertex")),
+                    d.get("label", "edge"),
+                    Vertex(reader.toObject(d["inV"]), d.get("inVLabel", "vertex")))
+
+
+class VertexPropertyDeserializer(_GraphSONTypeIO):
+    graphson_type = "g:VertexProperty"
+
+    @classmethod
+    def objectify(cls, d, reader):
+        vertex = Vertex(reader.toObject(d.get("vertex"))) if "vertex" in d else None
+        return VertexProperty(reader.toObject(d["id"]),
+                              d["label"],
+                              reader.toObject(d["value"]),
+                              vertex)
+
+
+class PropertyDeserializer(_GraphSONTypeIO):
+    graphson_type = "g:Property"
+
+    @classmethod
+    def objectify(cls, d, reader):
+        element = reader.toObject(d["element"]) if "element" in d else None
+        return Property(d["key"], reader.toObject(d["value"]), element)
+
+
+class PathDeserializer(_GraphSONTypeIO):
+    graphson_type = "g:Path"
+
+    @classmethod
+    def objectify(cls, d, reader):
+        labels = [set(label) for label in d["labels"]]
+        objects = [reader.toObject(o) for o in d["objects"]]
+        return Path(labels, objects)
+
+
+class TraversalMetricsDeserializer(_GraphSONTypeIO):
+    graphson_type = "g:TraversalMetrics"
+
+    @classmethod
+    def objectify(cls, d, reader):
+        return reader.toObject(d)
+
+
+class MetricsDeserializer(_GraphSONTypeIO):
+    graphson_type = "g:Metrics"
+
+    @classmethod
+    def objectify(cls, d, reader):
+        return reader.toObject(d)
diff --git a/gremlin-python/src/main/python/gremlin_python/structure/io/graphsonV3d0.py b/gremlin-python/src/main/python/gremlin_python/structure/io/graphsonV3d0.py
new file mode 100644
index 0000000..9ba2127
--- /dev/null
+++ b/gremlin-python/src/main/python/gremlin_python/structure/io/graphsonV3d0.py
@@ -0,0 +1,750 @@
+# 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.
+import calendar
+import datetime
+import json
+import uuid
+import math
+from collections import OrderedDict
+from decimal import *
+import logging
+from datetime import timedelta
+
+import six
+from aenum import Enum
+from isodate import parse_duration, duration_isoformat
+
+from gremlin_python import statics
+from gremlin_python.statics import FloatType, FunctionType, IntType, LongType, TypeType, DictType, ListType, SetType, SingleByte, ByteBufferType, SingleChar
+from gremlin_python.process.traversal import Binding, Bytecode, Direction, P, TextP, Traversal, Traverser, TraversalStrategy, T
+from gremlin_python.structure.graph import Edge, Property, Vertex, VertexProperty, Path
+from gremlin_python.structure.io.util import HashableDict
+
+log = logging.getLogger(__name__)
+
+# When we fall back to a superclass's serializer, we iterate over this map.
+# We want that iteration order to be consistent, so we use an OrderedDict,
+# not a dict.
+_serializers = OrderedDict()
+_deserializers = {}
+
+class GraphSONTypeType(type):
+    def __new__(mcs, name, bases, dct):
+        cls = super(GraphSONTypeType, mcs).__new__(mcs, name, bases, dct)
+        if not name.startswith('_'):
+            if cls.python_type:
+                _serializers[cls.python_type] = cls
+            if cls.graphson_type:
+                _deserializers[cls.graphson_type] = cls
+        return cls
+
+
+class GraphSONUtil(object):
+    TYPE_KEY = "@type"
+    VALUE_KEY = "@value"
+
+    @classmethod
+    def typedValue(cls, type_name, value, prefix="g"):
+        out = {cls.TYPE_KEY: cls.formatType(prefix, type_name)}
+        if value is not None:
+            out[cls.VALUE_KEY] = value
+        return out
+
+    @classmethod
+    def formatType(cls, prefix, type_name):
+        return "%s:%s" % (prefix, type_name)
+
+
+# Read/Write classes split to follow precedence of the Java API
+class GraphSONWriter(object):
+    def __init__(self, serializer_map=None):
+        """
+        :param serializer_map: map from Python type to serializer instance implementing `dictify`
+        """
+        self.serializers = _serializers.copy()
+        if serializer_map:
+            self.serializers.update(serializer_map)
+
+    def writeObject(self, objectData):
+        # to JSON
+        return json.dumps(self.toDict(objectData), separators=(',', ':'))
+
+    def toDict(self, obj):
+        """
+        Encodes python objects in GraphSON type-tagged dict values
+        """
+        try:
+            return self.serializers[type(obj)].dictify(obj, self)
+        except KeyError:
+            for key, serializer in self.serializers.items():
+                if isinstance(obj, key):
+                    return serializer.dictify(obj, self)
+
+        if isinstance(obj, dict):
+            return dict((self.toDict(k), self.toDict(v)) for k, v in obj.items())
+        elif isinstance(obj, set):
+            return set([self.toDict(o) for o in obj])
+        elif isinstance(obj, list):
+            return [self.toDict(o) for o in obj]
+        else:
+            return obj
+
+
+class GraphSONReader(object):
+    def __init__(self, deserializer_map=None):
+        """
+        :param deserializer_map: map from GraphSON type tag to deserializer instance implementing `objectify`
+        """
+        self.deserializers = _deserializers.copy()
+        if deserializer_map:
+            self.deserializers.update(deserializer_map)
+
+    def readObject(self, jsonData):
+        # from JSON
+        return self.toObject(json.loads(jsonData))
+
+    def toObject(self, obj):
+        """
+        Unpacks GraphSON type-tagged dict values into objects mapped in self.deserializers
+        """
+        if isinstance(obj, dict):
+            try:
+                return self.deserializers[obj[GraphSONUtil.TYPE_KEY]].objectify(obj[GraphSONUtil.VALUE_KEY], self)
+            except KeyError:
+                pass
+            return dict((self.toObject(k), self.toObject(v)) for k, v in obj.items())
+        elif isinstance(obj, set):
+            return set([self.toObject(o) for o in obj])
+        elif isinstance(obj, list):
+            return [self.toObject(o) for o in obj]
+        else:
+            return obj
+
+
+@six.add_metaclass(GraphSONTypeType)
+class _GraphSONTypeIO(object):
+    python_type = None
+    graphson_type = None
+
+    symbolMap = {"global_": "global", "as_": "as", "in_": "in", "and_": "and",
+                 "or_": "or", "is_": "is", "not_": "not", "from_": "from",
+                 "set_": "set", "list_": "list", "all_": "all", "with_": "with",
+                 "filter_": "filter", "id_": "id", "max_": "max", "min_": "min", "sum_": "sum"}
+
+    @classmethod
+    def unmangleKeyword(cls, symbol):
+        return cls.symbolMap.get(symbol, symbol)
+
+    def dictify(self, obj, writer):
+        raise NotImplementedError()
+
+    def objectify(self, d, reader):
+        raise NotImplementedError()
+
+
+class _BytecodeSerializer(_GraphSONTypeIO):
+    @classmethod
+    def _dictify_instructions(cls, instructions, writer):
+        out = []
+        for instruction in instructions:
+            inst = [instruction[0]]
+            inst.extend(writer.toDict(arg) for arg in instruction[1:])
+            out.append(inst)
+        return out
+
+    @classmethod
+    def dictify(cls, bytecode, writer):
+        if isinstance(bytecode, Traversal):
+            bytecode = bytecode.bytecode
+        out = {}
+        if bytecode.source_instructions:
+            out["source"] = cls._dictify_instructions(bytecode.source_instructions, writer)
+        if bytecode.step_instructions:
+            out["step"] = cls._dictify_instructions(bytecode.step_instructions, writer)
+        return GraphSONUtil.typedValue("Bytecode", out)
+
+
+class TraversalSerializer(_BytecodeSerializer):
+    python_type = Traversal
+
+
+class BytecodeSerializer(_BytecodeSerializer):
+    python_type = Bytecode
+
+
+class VertexSerializer(_GraphSONTypeIO):
+    python_type = Vertex
+    graphson_type = "g:Vertex"
+
+    @classmethod
+    def dictify(cls, vertex, writer):
+        return GraphSONUtil.typedValue("Vertex", {"id": writer.toDict(vertex.id),
+                                                  "label": writer.toDict(vertex.label)})
+
+
+class EdgeSerializer(_GraphSONTypeIO):
+    python_type = Edge
+    graphson_type = "g:Edge"
+
+    @classmethod
+    def dictify(cls, edge, writer):
+        return GraphSONUtil.typedValue("Edge", {"id": writer.toDict(edge.id),
+                                                "outV": writer.toDict(edge.outV.id),
+                                                "outVLabel": writer.toDict(edge.outV.label),
+                                                "label": writer.toDict(edge.label),
+                                                "inV": writer.toDict(edge.inV.id),
+                                                "inVLabel": writer.toDict(edge.inV.label)})
+
+
+class VertexPropertySerializer(_GraphSONTypeIO):
+    python_type = VertexProperty
+    graphson_type = "g:VertexProperty"
+
+    @classmethod
+    def dictify(cls, vertex_property, writer):
+        return GraphSONUtil.typedValue("VertexProperty", {"id": writer.toDict(vertex_property.id),
+                                                          "label": writer.toDict(vertex_property.label),
+                                                          "value": writer.toDict(vertex_property.value),
+                                                          "vertex": writer.toDict(vertex_property.vertex.id)})
+
+
+class PropertySerializer(_GraphSONTypeIO):
+    python_type = Property
+    graphson_type = "g:Property"
+
+    @classmethod
+    def dictify(cls, property, writer):
+        elementDict = writer.toDict(property.element)
+        if elementDict is not None:
+            valueDict = elementDict["@value"]
+            if "outVLabel" in valueDict:
+                del valueDict["outVLabel"]
+            if "inVLabel" in valueDict:
+                del valueDict["inVLabel"]
+            if "properties" in valueDict:
+                del valueDict["properties"]
+            if "value" in valueDict:
+                del valueDict["value"]
+        return GraphSONUtil.typedValue("Property", {"key": writer.toDict(property.key),
+                                                    "value": writer.toDict(property.value),
+                                                    "element": elementDict})
+
+
+class TraversalStrategySerializer(_GraphSONTypeIO):
+    python_type = TraversalStrategy
+
+    @classmethod
+    def dictify(cls, strategy, writer):
+        configuration = {}
+        for key in strategy.configuration:
+            configuration[key] = writer.toDict(strategy.configuration[key])
+        return GraphSONUtil.typedValue(strategy.strategy_name, configuration)
+
+
+class TraverserIO(_GraphSONTypeIO):
+    python_type = Traverser
+    graphson_type = "g:Traverser"
+
+    @classmethod
+    def dictify(cls, traverser, writer):
+        return GraphSONUtil.typedValue("Traverser", {"value": writer.toDict(traverser.object),
+                                                     "bulk": writer.toDict(traverser.bulk)})
+
+    @classmethod
+    def objectify(cls, d, reader):
+        return Traverser(reader.toObject(d["value"]),
+                         reader.toObject(d["bulk"]))
+
+
+class EnumSerializer(_GraphSONTypeIO):
+    python_type = Enum
+
+    @classmethod
+    def dictify(cls, enum, _):
+        return GraphSONUtil.typedValue(cls.unmangleKeyword(type(enum).__name__),
+                                       cls.unmangleKeyword(str(enum.name)))
+
+
+class PSerializer(_GraphSONTypeIO):
+    python_type = P
+
+    @classmethod
+    def dictify(cls, p, writer):
+        out = {"predicate": p.operator,
+               "value": [writer.toDict(p.value), writer.toDict(p.other)] if p.other is not None else
+               writer.toDict(p.value)}
+        return GraphSONUtil.typedValue("P", out)
+
+
+class TextPSerializer(_GraphSONTypeIO):
+    python_type = TextP
+
+    @classmethod
+    def dictify(cls, p, writer):
+        out = {"predicate": p.operator,
+               "value": [writer.toDict(p.value), writer.toDict(p.other)] if p.other is not None else
+               writer.toDict(p.value)}
+        return GraphSONUtil.typedValue("TextP", out)
+
+
+class BindingSerializer(_GraphSONTypeIO):
+    python_type = Binding
+
+    @classmethod
+    def dictify(cls, binding, writer):
+        out = {"key": binding.key,
+               "value": writer.toDict(binding.value)}
+        return GraphSONUtil.typedValue("Binding", out)
+
+
+class LambdaSerializer(_GraphSONTypeIO):
+    python_type = FunctionType
+
+    @classmethod
+    def dictify(cls, lambda_object, writer):
+        lambda_result = lambda_object()
+        script = lambda_result if isinstance(lambda_result, str) else lambda_result[0]
+        language = statics.default_lambda_language if isinstance(lambda_result, str) else lambda_result[1]
+        out = {"script": script,
+               "language": language}
+        if language == "gremlin-groovy" and "->" in script:
+            # if the user has explicitly added parameters to the groovy closure then we can easily detect one or two
+            # arg lambdas - if we can't detect 1 or 2 then we just go with "unknown"
+            args = script[0:script.find("->")]
+            out["arguments"] = 2 if "," in args else 1
+        else:
+            out["arguments"] = -1
+
+        return GraphSONUtil.typedValue("Lambda", out)
+
+
+class TypeSerializer(_GraphSONTypeIO):
+    python_type = TypeType
+
+    @classmethod
+    def dictify(cls, typ, writer):
+        return writer.toDict(typ())
+
+
+class UUIDIO(_GraphSONTypeIO):
+    python_type = uuid.UUID
+    graphson_type = "g:UUID"
+    graphson_base_type = "UUID"
+
+    @classmethod
+    def dictify(cls, obj, writer):
+        return GraphSONUtil.typedValue(cls.graphson_base_type, str(obj))
+
+    @classmethod
+    def objectify(cls, d, reader):
+        return cls.python_type(d)
+
+
+class DateIO(_GraphSONTypeIO):
+    python_type = datetime.datetime
+    graphson_type = "g:Date"
+    graphson_base_type = "Date"
+
+    @classmethod
+    def dictify(cls, obj, writer):
+        try:
+            timestamp_seconds = calendar.timegm(obj.utctimetuple())
+            pts = timestamp_seconds * 1e3 + getattr(obj, 'microsecond', 0) / 1e3
+        except AttributeError:
+            pts = calendar.timegm(obj.timetuple()) * 1e3
+
+        ts = int(round(pts))
+        return GraphSONUtil.typedValue(cls.graphson_base_type, ts)
+
+    @classmethod
+    def objectify(cls, ts, reader):
+        # Python timestamp expects seconds
+        return datetime.datetime.utcfromtimestamp(ts / 1000.0)
+
+
+# Based on current implementation, this class must always be declared before FloatIO.
+# Seems pretty fragile for future maintainers. Maybe look into this.
+class TimestampIO(_GraphSONTypeIO):
+    """A timestamp in Python is type float"""
+    python_type = statics.timestamp
+    graphson_type = "g:Timestamp"
+    graphson_base_type = "Timestamp"
+
+    @classmethod
+    def dictify(cls, obj, writer):
+        # Java timestamp expects milliseconds integer
+        # Have to use int because of legacy Python
+        ts = int(round(obj * 1000))
+        return GraphSONUtil.typedValue(cls.graphson_base_type, ts)
+
+    @classmethod
+    def objectify(cls, ts, reader):
+        # Python timestamp expects seconds
+        return cls.python_type(ts / 1000.0)
+
+
+class _NumberIO(_GraphSONTypeIO):
+    @classmethod
+    def dictify(cls, n, writer):
+        if isinstance(n, bool):  # because isinstance(False, int) and isinstance(True, int)
+            return n
+        return GraphSONUtil.typedValue(cls.graphson_base_type, n)
+
+    @classmethod
+    def objectify(cls, v, _):
+        return cls.python_type(v)
+
+
+class ListIO(_GraphSONTypeIO):
+    python_type = ListType
+    graphson_type = "g:List"
+
+    @classmethod
+    def dictify(cls, l, writer):
+        new_list = []
+        for obj in l:
+            new_list.append(writer.toDict(obj))
+        return GraphSONUtil.typedValue("List", new_list)
+
+    @classmethod
+    def objectify(cls, l, reader):
+        new_list = []
+        for obj in l:
+            new_list.append(reader.toObject(obj))
+        return new_list
+
+
+class SetIO(_GraphSONTypeIO):
+    python_type = SetType
+    graphson_type = "g:Set"
+
+    @classmethod
+    def dictify(cls, s, writer):
+        new_list = []
+        for obj in s:
+            new_list.append(writer.toDict(obj))
+        return GraphSONUtil.typedValue("Set", new_list)
+
+    @classmethod
+    def objectify(cls, s, reader):
+        """
+        By default, returns a python set
+
+        In case Java returns numeric values of different types which
+        python don't recognize, coerce and return a list.
+        See comments of TINKERPOP-1844 for more details
+        """
+        new_list = [reader.toObject(obj) for obj in s]
+        new_set = set(new_list)
+        if len(new_list) != len(new_set):
+            log.warning("Coercing g:Set to list due to java numeric values. "
+                        "See TINKERPOP-1844 for more details.")
+            return new_list
+
+        return new_set
+
+
+class MapType(_GraphSONTypeIO):
+    python_type = DictType
+    graphson_type = "g:Map"
+
+    @classmethod
+    def dictify(cls, d, writer):
+        l = []
+        for key in d:
+            l.append(writer.toDict(key))
+            l.append(writer.toDict(d[key]))
+        return GraphSONUtil.typedValue("Map", l)
+
+    @classmethod
+    def objectify(cls, l, reader):
+        new_dict = {}
+        if len(l) > 0:
+            x = 0
+            while x < len(l):
+                new_dict[HashableDict.of(reader.toObject(l[x]))] = reader.toObject(l[x + 1])
+                x = x + 2
+        return new_dict
+
+
+class BulkSetIO(_GraphSONTypeIO):
+    graphson_type = "g:BulkSet"
+
+    @classmethod
+    def objectify(cls, l, reader):
+        new_list = []
+
+        # this approach basically mimics what currently existed in 3.3.4 and prior versions where BulkSet is
+        # basically just coerced to list. the limitation here is that if the value of a bulk exceeds the size of
+        # a list (into the long space) then stuff won't work nice.
+        if len(l) > 0:
+            x = 0
+            while x < len(l):
+                obj = reader.toObject(l[x])
+                bulk = reader.toObject(l[x + 1])
+                for y in range(bulk):
+                    new_list.append(obj)
+                x = x + 2
+        return new_list
+
+
+class FloatIO(_NumberIO):
+    python_type = FloatType
+    graphson_type = "g:Float"
+    graphson_base_type = "Float"
+
+    @classmethod
+    def dictify(cls, n, writer):
+        if isinstance(n, bool):  # because isinstance(False, int) and isinstance(True, int)
+            return n
+        elif math.isnan(n):
+            return GraphSONUtil.typedValue(cls.graphson_base_type, "NaN")
+        elif math.isinf(n) and n > 0:
+            return GraphSONUtil.typedValue(cls.graphson_base_type, "Infinity")
+        elif math.isinf(n) and n < 0:
+            return GraphSONUtil.typedValue(cls.graphson_base_type, "-Infinity")
+        else:
+            return GraphSONUtil.typedValue(cls.graphson_base_type, n)
+
+    @classmethod
+    def objectify(cls, v, _):
+        if isinstance(v, str):
+            if v == 'NaN':
+                return float('nan')
+            elif v == "Infinity":
+                return float('inf')
+            elif v == "-Infinity":
+                return float('-inf')
+
+        return cls.python_type(v)
+
+
+class BigDecimalIO(_NumberIO):
+    python_type = Decimal
+    graphson_type = "gx:BigDecimal"
+    graphson_base_type = "BigDecimal"
+
+    @classmethod
+    def dictify(cls, n, writer):
+        if isinstance(n, bool):  # because isinstance(False, int) and isinstance(True, int)
+            return n
+        elif math.isnan(n):
+            return GraphSONUtil.typedValue(cls.graphson_base_type, "NaN", "gx")
+        elif math.isinf(n) and n > 0:
+            return GraphSONUtil.typedValue(cls.graphson_base_type, "Infinity", "gx")
+        elif math.isinf(n) and n < 0:
+            return GraphSONUtil.typedValue(cls.graphson_base_type, "-Infinity", "gx")
+        else:
+            return GraphSONUtil.typedValue(cls.graphson_base_type, str(n), "gx")
+
+    @classmethod
+    def objectify(cls, v, _):
+        if isinstance(v, str):
+            if v == 'NaN':
+                return Decimal('nan')
+            elif v == "Infinity":
+                return Decimal('inf')
+            elif v == "-Infinity":
+                return Decimal('-inf')
+
+        return Decimal(v)
+
+
+class DoubleIO(FloatIO):
+    graphson_type = "g:Double"
+    graphson_base_type = "Double"
+
+
+class Int64IO(_NumberIO):
+    python_type = LongType
+    graphson_type = "g:Int64"
+    graphson_base_type = "Int64"
+
+    @classmethod
+    def dictify(cls, n, writer):
+        # if we exceed Java long range then we need a BigInteger
+        if isinstance(n, bool):
+            return n
+        elif n < -9223372036854775808 or n > 9223372036854775807:
+            return GraphSONUtil.typedValue("BigInteger", str(n), "gx")
+        else:
+            return GraphSONUtil.typedValue(cls.graphson_base_type, n)
+
+
+class BigIntegerIO(Int64IO):
+    graphson_type = "gx:BigInteger"
+
+
+class Int32IO(Int64IO):
+    python_type = IntType
+    graphson_type = "g:Int32"
+    graphson_base_type = "Int32"
+
+    @classmethod
+    def dictify(cls, n, writer):
+        # if we exceed Java int range then we need a long
+        if isinstance(n, bool):
+            return n
+        elif n < -9223372036854775808 or n > 9223372036854775807:
+            return GraphSONUtil.typedValue("BigInteger", str(n), "gx")
+        elif n < -2147483648 or n > 2147483647:
+            return GraphSONUtil.typedValue("Int64", n)
+        else:
+            return GraphSONUtil.typedValue(cls.graphson_base_type, n)
+
+class ByteIO(_NumberIO):
+    python_type = SingleByte
+    graphson_type = "gx:Byte"
+    graphson_base_type = "Byte"
+
+    @classmethod
+    def dictify(cls, n, writer):
+        if isinstance(n, bool):  # because isinstance(False, int) and isinstance(True, int)
+            return n
+        return GraphSONUtil.typedValue(cls.graphson_base_type, n, "gx")
+
+    @classmethod
+    def objectify(cls, v, _):
+        return int.__new__(SingleByte, v)
+
+
+class ByteBufferIO(_GraphSONTypeIO):
+    python_type = ByteBufferType
+    graphson_type = "gx:ByteBuffer"
+    graphson_base_type = "ByteBuffer"
+
+    @classmethod
+    def dictify(cls, n, writer):
+        return GraphSONUtil.typedValue(cls.graphson_base_type, "".join(chr(x) for x in n), "gx")
+
+    @classmethod
+    def objectify(cls, v, _):
+        return cls.python_type(v, "utf8")
+
+
+class CharIO(_GraphSONTypeIO):
+    python_type = SingleChar
+    graphson_type = "gx:Char"
+    graphson_base_type = "Char"
+
+    @classmethod
+    def dictify(cls, n, writer):
+        return GraphSONUtil.typedValue(cls.graphson_base_type, n, "gx")
+
+    @classmethod
+    def objectify(cls, v, _):
+        return str.__new__(SingleChar, v)
+
+
+class DurationIO(_GraphSONTypeIO):
+    python_type = timedelta
+    graphson_type = "gx:Duration"
+    graphson_base_type = "Duration"
+
+    @classmethod
+    def dictify(cls, n, writer):
+        return GraphSONUtil.typedValue(cls.graphson_base_type, duration_isoformat(n), "gx")
+
+    @classmethod
+    def objectify(cls, v, _):
+        return parse_duration(v)
+
+
+class VertexDeserializer(_GraphSONTypeIO):
+    graphson_type = "g:Vertex"
+
+    @classmethod
+    def objectify(cls, d, reader):
+        return Vertex(reader.toObject(d["id"]), d.get("label", "vertex"))
+
+
+class EdgeDeserializer(_GraphSONTypeIO):
+    graphson_type = "g:Edge"
+
+    @classmethod
+    def objectify(cls, d, reader):
+        return Edge(reader.toObject(d["id"]),
+                    Vertex(reader.toObject(d["outV"]), d.get("outVLabel", "vertex")),
+                    d.get("label", "edge"),
+                    Vertex(reader.toObject(d["inV"]), d.get("inVLabel", "vertex")))
+
+
+class VertexPropertyDeserializer(_GraphSONTypeIO):
+    graphson_type = "g:VertexProperty"
+
+    @classmethod
+    def objectify(cls, d, reader):
+        vertex = Vertex(reader.toObject(d.get("vertex"))) if "vertex" in d else None
+        return VertexProperty(reader.toObject(d["id"]),
+                              d["label"],
+                              reader.toObject(d["value"]),
+                              vertex)
+
+
+class PropertyDeserializer(_GraphSONTypeIO):
+    graphson_type = "g:Property"
+
+    @classmethod
+    def objectify(cls, d, reader):
+        element = reader.toObject(d["element"]) if "element" in d else None
+        return Property(d["key"], reader.toObject(d["value"]), element)
+
+
+class PathDeserializer(_GraphSONTypeIO):
+    graphson_type = "g:Path"
+
+    @classmethod
+    def objectify(cls, d, reader):
+        return Path(reader.toObject(d["labels"]), reader.toObject(d["objects"]))
+
+
+class TDeserializer(_GraphSONTypeIO):
+    graphson_type = "g:T"
+
+    @classmethod
+    def objectify(cls, d, reader):
+        return T[d]
+
+
+class DirectionIO(_GraphSONTypeIO):
+    graphson_type = "g:Direction"
+    graphson_base_type = "Direction"
+    python_type = Direction
+
+    @classmethod
+    def dictify(cls, d, writer):
+        return GraphSONUtil.typedValue(cls.graphson_base_type, d.name, "g")
+
+    @classmethod
+    def objectify(cls, d, reader):
+        return Direction[d]
+
+
+class TraversalMetricsDeserializer(_GraphSONTypeIO):
+    graphson_type = "g:TraversalMetrics"
+
+    @classmethod
+    def objectify(cls, d, reader):
+        return reader.toObject(d)
+
+
+class MetricsDeserializer(_GraphSONTypeIO):
+    graphson_type = "g:Metrics"
+
+    @classmethod
+    def objectify(cls, d, reader):
+        return reader.toObject(d)
diff --git a/gremlin-python/src/main/python/gremlin_python/structure/io/util.py b/gremlin-python/src/main/python/gremlin_python/structure/io/util.py
new file mode 100644
index 0000000..e57a7e9
--- /dev/null
+++ b/gremlin-python/src/main/python/gremlin_python/structure/io/util.py
@@ -0,0 +1,40 @@
+# 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.
+
+
+class HashableDict(dict):
+    def __hash__(self):
+        try:
+            return hash(tuple(sorted(self.items())))
+        except:
+            return hash(tuple(sorted(str(x) for x in self.items())))
+
+    @classmethod
+    def of(cls, o):
+        if isinstance(o, (tuple, set, list)):
+            return tuple([cls.of(e) for e in o])
+        elif not isinstance(o, (dict, HashableDict)):
+            return o
+
+        new_o = HashableDict()
+        for k, v in o.items():
+            if isinstance(k, (set, list)):
+                new_o[tuple(k)] = cls.of(v)
+            else:
+                new_o[k] = cls.of(v)
+        return new_o
+
diff --git a/gremlin-python/src/main/python/radish/feature_steps.py b/gremlin-python/src/main/python/radish/feature_steps.py
new file mode 100644
index 0000000..fe1ea44
--- /dev/null
+++ b/gremlin-python/src/main/python/radish/feature_steps.py
@@ -0,0 +1,230 @@
+#
+# 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.
+#
+
+import json
+import re
+from gremlin_python.statics import long
+from gremlin_python.structure.graph import Path
+from gremlin_python.process.anonymous_traversal import traversal
+from gremlin_python.process.graph_traversal import __
+from gremlin_python.process.traversal import Barrier, Cardinality, P, TextP, Pop, Scope, Column, Order, Direction, T, Pick, Operator, IO, WithOptions
+from radish import given, when, then, world
+from hamcrest import *
+
+outV = __.outV
+label = __.label
+inV = __.inV
+project = __.project
+tail = __.tail
+
+ignores = []
+
+
+@given("the {graph_name:w} graph")
+def choose_graph(step, graph_name):
+    step.context.graph_name = graph_name
+    step.context.g = traversal().withRemote(step.context.remote_conn[graph_name])
+
+
+@given("the graph initializer of")
+def initialize_graph(step):
+    t = step.context.traversals.pop(0)(g=step.context.g)
+
+    # just be sure that the traversal returns something to prove that it worked to some degree. probably
+    # is overkill to try to assert the complete success of this init operation. presumably the test
+    # suite would fail elsewhere if this didn't work which would help identify a problem.
+    result = t.toList()
+    assert len(result) > 0
+
+
+@given("an unsupported test")
+def unsupported_scenario(step):
+    # this is a do nothing step as the test can't be supported for whatever reason
+    return
+
+
+@given("using the parameter {param_name:w} of P.{p_val:w}({param:QuotedString})")
+def add_p_parameter(step, param_name, p_val, param):
+    if not hasattr(step.context, "traversal_params"):
+        step.context.traversal_params = {}
+
+    step.context.traversal_params[param_name] = getattr(P, p_val)(_convert(param.replace('\\"', '"'), step.context))
+
+
+@given("using the parameter {param_name:w} defined as {param:QuotedString}")
+def add_parameter(step, param_name, param):
+    if not hasattr(step.context, "traversal_params"):
+        step.context.traversal_params = {}
+
+    step.context.traversal_params[param_name] = _convert(param.replace('\\"', '"'), step.context)
+
+
+@given("the traversal of")
+def translate_traversal(step):
+    step.context.ignore = step.text in ignores
+    p = step.context.traversal_params if hasattr(step.context, "traversal_params") else {}
+    p['g'] = step.context.g
+    step.context.traversal = step.context.traversals.pop(0)(**p)
+
+
+@when("iterated to list")
+def iterate_the_traversal(step):
+    if step.context.ignore:
+        return
+    
+    step.context.result = list(map(lambda x: _convert_results(x), step.context.traversal.toList()))
+
+
+@when("iterated next")
+def next_the_traversal(step):
+    if step.context.ignore:
+        return
+
+    step.context.result = list(map(lambda x: _convert_results(x), step.context.traversal.next()))
+
+
+@then("the result should be {characterized_as:w}")
+def assert_result(step, characterized_as):
+    if step.context.ignore:
+        return
+
+    if characterized_as == "empty":        # no results
+        assert_that(len(step.context.result), equal_to(0))
+    elif characterized_as == "ordered":    # results asserted in the order of the data table
+        _table_assertion(step.table, step.context.result, step.context, True)
+    elif characterized_as == "unordered":  # results asserted in any order
+        _table_assertion(step.table, step.context.result, step.context, False)
+    elif characterized_as == "of":         # results may be of any of the specified items in the data table
+        _any_assertion(step.table, step.context.result, step.context)
+    else:
+        raise ValueError("unknown data characterization of " + characterized_as)
+
+
+@then("the graph should return {count:d} for count of {traversal_string:QuotedString}")
+def assert_side_effects(step, count, traversal_string):
+    if step.context.ignore:
+        return
+
+    p = step.context.traversal_params if hasattr(step.context, "traversal_params") else {}
+    p['g'] = step.context.g
+    t = step.context.traversals.pop(0)(**p)
+
+    assert_that(t.count().next(), equal_to(count))
+
+
+@then("the result should have a count of {count:d}")
+def assert_count(step, count):
+    assert_that(len(list(step.context.result)), equal_to(count))
+
+
+@then("nothing should happen because")
+def nothing_happening(step):
+    return
+
+
+def _convert(val, ctx):
+    graph_name = ctx.graph_name
+    if isinstance(val, dict):                                            # convert dictionary keys/values
+        n = {}
+        for key, value in val.items():
+            k = _convert(key, ctx)
+            # convert to tuple key if list/set as neither are hashable
+            n[tuple(k) if isinstance(k, (set, list)) else k] = _convert(value, ctx)
+        return n
+    elif isinstance(val, str) and re.match(r"^l\[.*\]$", val):           # parse list
+        return [] if val == "l[]" else list(map((lambda x: _convert(x, ctx)), val[2:-1].split(",")))
+    elif isinstance(val, str) and re.match(r"^s\[.*\]$", val):           # parse set
+        return set() if val == "s[]" else set(map((lambda x: _convert(x, ctx)), val[2:-1].split(",")))
+    elif isinstance(val, str) and re.match(r"^d\[.*\]\.[ilfdm]$", val):  # parse numeric
+        return float(val[2:-3]) if val[2:-3].__contains__(".") else long(val[2:-3])
+    elif isinstance(val, str) and re.match(r"^v\[.*\]\.id$", val):       # parse vertex id
+        return __find_cached_element(ctx, graph_name, val[2:-4], "v").id
+    elif isinstance(val, str) and re.match(r"^v\[.*\]\.sid$", val):      # parse vertex id as string
+        return str(__find_cached_element(ctx, graph_name, val[2:-5], "v").id)
+    elif isinstance(val, str) and re.match(r"^v\[.*\]$", val):           # parse vertex
+        return __find_cached_element(ctx, graph_name, val[2:-1], "v")
+    elif isinstance(val, str) and re.match(r"^e\[.*\]\.id$", val):       # parse edge id
+        return __find_cached_element(ctx, graph_name, val[2:-4], "e").id
+    elif isinstance(val, str) and re.match(r"^e\[.*\]\.sid$", val):      # parse edge id as string
+        return str(__find_cached_element(ctx, graph_name, val[2:-5], "e").id)
+    elif isinstance(val, str) and re.match(r"^e\[.*\]$", val):           # parse edge
+        return __find_cached_element(ctx, graph_name, val[2:-1], "e")
+    elif isinstance(val, str) and re.match(r"^m\[.*\]$", val):           # parse json as a map
+        return _convert(json.loads(val[2:-1]), ctx)
+    elif isinstance(val, str) and re.match(r"^p\[.*\]$", val):           # parse path
+        path_objects = list(map((lambda x: _convert(x, ctx)), val[2:-1].split(",")))
+        return Path([set([])], path_objects)
+    elif isinstance(val, str) and re.match(r"^c\[.*\]$", val):           # parse lambda/closure
+        return lambda: (val[2:-1], "gremlin-groovy")
+    elif isinstance(val, str) and re.match(r"^t\[.*\]$", val):           # parse instance of T enum
+        return T[val[2:-1]]
+    elif isinstance(val, str) and re.match(r"^D\[.*\]$", val):           # parse instance of Direction enum
+        return Direction[val[2:-1]]
+    elif isinstance(val, str) and re.match(r"^null$", val):              # parse null to None
+        return None
+    else:
+        return val
+
+
+def __find_cached_element(ctx, graph_name, identifier, element_type):
+    if graph_name == "empty":
+        cache = world.create_lookup_v(ctx.remote_conn["empty"]) if element_type == "v" else world.create_lookup_e(ctx.remote_conn["empty"])
+    else:
+        cache = ctx.lookup_v[graph_name] if element_type == "v" else ctx.lookup_e[graph_name]
+
+    return cache[identifier]
+
+
+def _convert_results(val):
+    if isinstance(val, Path):
+        # kill out labels as they aren't in the assertion logic
+        return Path([set([])], val.objects)
+    else:
+        return val
+
+
+def _any_assertion(data, result, ctx):
+    converted = [_convert(line['result'], ctx) for line in data]
+    for r in result:
+        assert_that(r, is_in(converted))
+
+
+def _table_assertion(data, result, ctx, ordered):
+    # results from traversal should have the same number of entries as the feature data table
+    assert_that(len(result), equal_to(len(data)), "result:" + str(result))
+
+    results_to_test = list(result)
+
+    # finds a match in the results for each line of data to assert and then removes that item
+    # from the list - in the end there should be no items left over and each will have been asserted
+    for ix, line in enumerate(data):
+        val = _convert(line['result'], ctx)
+
+        # clear the labels since we don't define them in .feature files
+        if isinstance(val, Path):
+            val.labels = [set([])]
+
+        if ordered:
+            assert_that(results_to_test[ix], equal_to(val))
+        else:
+            assert_that(val, is_in(results_to_test))
+            results_to_test.remove(val)
+
+    if not ordered:
+        assert_that(len(results_to_test), is_(0))
diff --git a/gremlin-python/src/main/python/radish/gremlin.py b/gremlin-python/src/main/python/radish/gremlin.py
new file mode 100644
index 0000000..ae2c117
--- /dev/null
+++ b/gremlin-python/src/main/python/radish/gremlin.py
@@ -0,0 +1,667 @@
+#
+# 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.
+#
+
+
+
+#######################################################################################
+## Do NOT edit this file directly - generated by build/generate.groovy
+#######################################################################################
+
+
+from radish import world
+from gremlin_python.process.anonymous_traversal import traversal
+from gremlin_python.process.traversal import TraversalStrategy
+from gremlin_python.process.graph_traversal import __
+from gremlin_python.structure.graph import Graph
+from gremlin_python.process.traversal import Barrier, Cardinality, P, TextP, Pop, Scope, Column, Order, Direction, T, Pick, Operator, IO, WithOptions
+
+world.gremlins = {
+    'g_V_branchXlabel_eq_person__a_bX_optionXa__ageX_optionXb__langX_optionXb__nameX': [(lambda g, l1=None:g.V().branch(l1).option('a',__.age).option('b',__.lang).option('b',__.name))], 
+    'g_V_branchXlabel_isXpersonX_countX_optionX1__ageX_optionX0__langX_optionX0__nameX': [(lambda g, xx1=None,xx2=None:g.V().branch(__.label().is_('person').count()).option(xx1,__.age).option(xx2,__.lang).option(xx2,__.name))], 
+    'g_V_branchXlabel_isXpersonX_countX_optionX1__ageX_optionX0__langX_optionX0__nameX_optionXany__labelX': [(lambda g, xx1=None,xx2=None:g.V().branch(__.label().is_('person').count()).option(xx1,__.age).option(xx2,__.lang).option(xx2,__.name).option(Pick.any,__.label()))], 
+    'g_V_branchXageX_optionXltX30X__youngX_optionXgtX30X__oldX_optionXnone__on_the_edgeX': [(lambda g:g.V().hasLabel('person').branch(__.age).option(P.lt(30),__.constant('young')).option(P.gt(30),__.constant('old')).option(Pick.none,__.constant('on the edge')))], 
+    'g_V_branchXidentityX_optionXhasLabelXsoftwareX__inXcreatedX_name_order_foldX_optionXhasXname_vadasX__ageX_optionXneqX123X__bothE_countX': [(lambda g:g.V().branch(__.identity()).option(__.hasLabel('software'),__.in_('created').name.order().fold()).option(__.has('name','vadas'),__.age).option(P.neq(123),__.bothE().count()))], 
+    'g_V_chooseXout_countX_optionX2L_nameX_optionX3L_ageX': [(lambda g, xx1=None,xx2=None:g.V().choose(__.out().count()).option(xx1,__.name).option(xx2,__.age))], 
+    'g_V_chooseXlabel_eqXpersonX__outXknowsX__inXcreatedXX_name': [(lambda g, pred1=None:g.V().choose(pred1,__.out('knows'),__.in_('created')).name)], 
+    'g_V_chooseXhasLabelXpersonX_and_outXcreatedX__outXknowsX__identityX_name': [(lambda g:g.V().choose(__.hasLabel('person').and_().out('created'),__.out('knows'),__.identity()).name)], 
+    'g_V_chooseXlabelX_optionXblah__outXknowsXX_optionXbleep__outXcreatedXX_optionXnone__identityX_name': [(lambda g:g.V().choose(__.label()).option('blah',__.out('knows')).option('bleep',__.out('created')).option(Pick.none,__.identity()).name)], 
+    'g_V_chooseXoutXknowsX_count_isXgtX0XX__outXknowsXX_name': [(lambda g:g.V().choose(__.out('knows').count().is_(P.gt(0)),__.out('knows')).name)], 
+    'g_V_hasLabelXpersonX_asXp1X_chooseXoutEXknowsX__outXknowsXX_asXp2X_selectXp1_p2X_byXnameX': [(lambda g:g.V().hasLabel('person').as_('p1').choose(__.outE('knows'),__.out('knows')).as_('p2').select('p1','p2').by('name'))], 
+    'g_V_hasLabelXpersonX_chooseXageX__optionX27L__constantXyoungXX_optionXnone__constantXoldXX_groupCount': [(lambda g, xx1=None:g.V().hasLabel('person').choose(__.age).option(xx1,__.constant('young')).option(Pick.none,__.constant('old')).groupCount())], 
+    'g_injectX1X_chooseXisX1X__constantX10Xfold__foldX': [(lambda g, xx1=None,xx2=None:g.inject(xx2).choose(__.is_(xx2),__.constant(xx1).fold(),__.fold()))], 
+    'g_injectX2X_chooseXisX1X__constantX10Xfold__foldX': [(lambda g, xx1=None,xx3=None,xx2=None:g.inject(xx3).choose(__.is_(xx2),__.constant(xx1).fold(),__.fold()))], 
+    'g_V_localXpropertiesXlocationX_order_byXvalueX_limitX2XX_value': [(lambda g:g.V().local(__.properties('location').order().by(T.value,Order.asc)[0:2]).value())], 
+    'g_V_hasXlabel_personX_asXaX_localXoutXcreatedX_asXbXX_selectXa_bX_byXnameX_byXidX': [(lambda g:g.V().has(T.label,'person').as_('a').local(__.out('created').as_('b')).select('a','b').by('name').by(T.id))], 
+    'g_V_localXoutE_countX': [(lambda g:g.V().local(__.outE().count()))], 
+    'g_VX1X_localXoutEXknowsX_limitX1XX_inV_name': [(lambda g, vid1=None:g.V(vid1).local(__.outE('knows')[0:1]).inV().name)], 
+    'g_V_localXbothEXcreatedX_limitX1XX_otherV_name': [(lambda g:g.V().local(__.bothE('created')[0:1]).otherV().name)], 
+    'g_VX4X_localXbothEX1_createdX_limitX1XX': [(lambda g, vid4=None:g.V(vid4).local(__.bothE('created')[0:1]))], 
+    'g_VX4X_localXbothEXknows_createdX_limitX1XX': [(lambda g, vid4=None:g.V(vid4).local(__.bothE('knows','created')[0:1]))], 
+    'g_VX4X_localXbothE_limitX1XX_otherV_name': [(lambda g, vid4=None:g.V(vid4).local(__.bothE()[0:1]).otherV().name)], 
+    'g_VX4X_localXbothE_limitX2XX_otherV_name': [(lambda g, vid4=None:g.V(vid4).local(__.bothE()[0:2]).otherV().name)], 
+    'g_V_localXinEXknowsX_limitX2XX_outV_name': [(lambda g:g.V().local(__.inE('knows')[0:2]).outV().name)], 
+    'g_V_localXmatchXproject__created_person__person_name_nameX_selectXname_projectX_by_byXnameX': [(lambda g:g.V().local(__.match(__.as_('project').in_('created').as_('person'),__.as_('person').name.as_('name'))).select('name','project').by().by('name'))], 
+    'g_VX2X_optionalXoutXknowsXX': [(lambda g, vid2=None:g.V(vid2).optional(__.out('knows')))], 
+    'g_VX2X_optionalXinXknowsXX': [(lambda g, vid2=None:g.V(vid2).optional(__.in_('knows')))], 
+    'g_V_hasLabelXpersonX_optionalXoutXknowsX_optionalXoutXcreatedXXX_path': [(lambda g:g.V().hasLabel('person').optional(__.out('knows').optional(__.out('created'))).path())], 
+    'g_V_optionalXout_optionalXoutXX_path': [(lambda g:g.V().optional(__.out().optional(__.out())).path())], 
+    'g_VX1X_optionalXaddVXdogXX_label': [(lambda g, vid1=None:g.addV('person').property(T.id,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id,5).property('name','ripple').property('lang','java').as_('ripple').addV('person').property(T.id,6).property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property(T.id,7).property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property(T.id,8).property('weight',float(1.0)).addE('created').from_('marko').to('lop').property(T.id,9).property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property(T.id,10).property('weight',float(1.0)).addE('created').from_('josh').to('lop').property(T.id,11).property('weight',float(0.4)).addE('created').from_('peter').to('lop').property(T.id,12).property('weight',float(0.2))), (lambda g, vid1=None:g.V(vid1).optional(__.addV('dog')).label()), (lambda g, vid1=None:g.V())], 
+    'g_V_repeatXoutX_timesX2X_emit_path': [(lambda g:g.V().repeat(__.out()).times(2).emit().path())], 
+    'g_V_repeatXoutX_timesX2X_repeatXinX_timesX2X_name': [(lambda g:g.V().repeat(__.out()).times(2).repeat(__.in_()).times(2).name)], 
+    'g_V_repeatXoutX_timesX2X': [(lambda g:g.V().repeat(__.out()).times(2))], 
+    'g_V_repeatXoutX_timesX2X_emit': [(lambda g:g.V().repeat(__.out()).times(2).emit())], 
+    'g_VX1X_timesX2X_repeatXoutX_name': [(lambda g, vid1=None:g.V(vid1).times(2).repeat(__.out()).name)], 
+    'g_V_emit_timesX2X_repeatXoutX_path': [(lambda g:g.V().emit().times(2).repeat(__.out()).path())], 
+    'g_V_emit_repeatXoutX_timesX2X_path': [(lambda g:g.V().emit().repeat(__.out()).times(2).path())], 
+    'g_VX1X_emitXhasXlabel_personXX_repeatXoutX_name': [(lambda g, vid1=None:g.V(vid1).emit(__.has(T.label,'person')).repeat(__.out()).name)], 
+    'g_V_repeatXgroupCountXmX_byXnameX_outX_timesX2X_capXmX': [(lambda g:g.V().repeat(__.groupCount('m').by('name').out()).times(2).cap('m'))], 
+    'g_VX1X_repeatXgroupCountXmX_byXloopsX_outX_timesX3X_capXmX': [(lambda g, vid1=None:g.V(vid1).repeat(__.groupCount('m').by(__.loops()).out()).times(3).cap('m'))], 
+    'g_V_repeatXbothX_timesX10X_asXaX_out_asXbX_selectXa_bX': [(lambda g:g.V().repeat(__.both()).times(10).as_('a').out().as_('b').select('a','b').count())], 
+    'g_VX1X_repeatXoutX_untilXoutE_count_isX0XX_name': [(lambda g, vid1=None:g.V(vid1).repeat(__.out()).until(__.outE().count().is_(0)).name)], 
+    'g_V_repeatXbothX_untilXname_eq_marko_or_loops_gt_1X_groupCount_byXnameX': [(lambda g, pred1=None:g.V().repeat(__.both()).until(pred1).groupCount().by('name'))], 
+    'g_V_hasXname_markoX_repeatXoutE_inV_simplePathX_untilXhasXname_rippleXX_path_byXnameX_byXlabelX': [(lambda g:g.V().has('name','marko').repeat(__.outE().inV().simplePath()).until(__.has('name','ripple')).path().by('name').by(T.label))], 
+    'g_V_hasXloop_name_loopX_repeatXinX_timesX5X_path_by_name': [(lambda g:g.V().has('loops','name','loop').repeat(__.in_()).times(5).path().by('name'))], 
+    'g_V_repeatXout_repeatXoutX_timesX1XX_timesX1X_limitX1X_path_by_name': [(lambda g:g.V().repeat(__.out().repeat(__.out()).times(1)).times(1)[0:1].path().by('name'))], 
+    'g_V_repeatXoutXknowsXX_untilXrepeatXoutXcreatedXX_emitXhasXname_lopXXX_path_byXnameX': [(lambda g:g.V().repeat(__.out('knows')).until(__.repeat(__.out('created')).emit(__.has('name','lop'))).path().by('name'))], 
+    'g_V_repeatXrepeatXout_createdXX_untilXhasXname_rippleXXXemit_lang': [(lambda g:g.V().repeat(__.repeat(__.out('created')).until(__.has('name','ripple'))).emit().lang)], 
+    'g_V_untilXconstantXtrueXX_repeatXrepeatXout_createdXX_untilXhasXname_rippleXXXemit_lang': [(lambda g:g.V().until(__.constant(True)).repeat(__.repeat(__.out('created')).until(__.has('name','ripple'))).emit().lang)], 
+    'g_V_emit_repeatXa_outXknows_filterXloops_isX0XX_lang': [(lambda g:g.V().emit().repeat('a',__.out('knows').filter(__.loops('a').is_(0))).lang)], 
+    'g_VX3X_repeatXbothX_createdXX_untilXloops_is_40XXemit_repeatXin_knowsXX_emit_loopsXisX1Xdedup_values': [(lambda g, vid3=None:g.V(vid3).repeat(__.both('created')).until(__.loops().is_(40)).emit(__.repeat(__.in_('knows')).emit(__.loops().is_(1))).dedup().name)], 
+    'g_VX1X_repeatXrepeatXunionXout_uses_out_traversesXX_whereXloops_isX0X_timesX1X_timeX2X_name': [(lambda g, vid1=None:g.V(vid1).repeat(__.repeat(__.union(__.out('uses'),__.out('traverses')).where(__.loops().is_(0))).times(1)).times(2).name)], 
+    'g_V_repeatXa_outXknows_repeatXb_outXcreatedX_filterXloops_isX0XX_emit_lang': [(lambda g:g.V().repeat('a',__.out('knows').repeat('b',__.out('created').filter(__.loops('a').is_(0))).emit()).emit().lang)], 
+    'g_VX6X_repeatXa_bothXcreatedX_simplePathX_emitXrepeatXb_bothXknowsXX_untilXloopsXbX_asXb_whereXloopsXaX_asXbX_hasXname_vadasXX_dedup_name': [(lambda g, vid6=None:g.V(vid6).repeat('a',__.both('created').simplePath()).emit(__.repeat('b',__.both('knows')).until(__.loops('b').as_('b').where(__.loops('a').as_('b'))).has('name','vadas')).dedup().name)], 
+    'g_V_unionXout__inX_name': [(lambda g:g.V().union(__.out(),__.in_()).name)], 
+    'g_VX1X_unionXrepeatXoutX_timesX2X__outX_name': [(lambda g, vid1=None:g.V(vid1).union(__.repeat(__.out()).times(2),__.out()).name)], 
+    'g_V_chooseXlabel_is_person__unionX__out_lang__out_nameX__in_labelX': [(lambda g:g.V().choose(__.label().is_('person'),__.union(__.out().lang,__.out().name),__.in_().label()))], 
+    'g_V_chooseXlabel_is_person__unionX__out_lang__out_nameX__in_labelX_groupCount': [(lambda g:g.V().choose(__.label().is_('person'),__.union(__.out().lang,__.out().name),__.in_().label()).groupCount())], 
+    'g_V_unionXrepeatXunionXoutXcreatedX__inXcreatedXX_timesX2X__repeatXunionXinXcreatedX__outXcreatedXX_timesX2XX_label_groupCount': [(lambda g:g.V().union(__.repeat(__.union(__.out('created'),__.in_('created'))).times(2),__.repeat(__.union(__.in_('created'),__.out('created'))).times(2)).label().groupCount())], 
+    'g_VX1_2X_unionXoutE_count__inE_count__outE_weight_sumX': [(lambda g, vid2=None,vid1=None:g.V(vid1,vid2).union(__.outE().count(),__.inE().count(),__.outE().weight.sum()))], 
+    'g_VX1_2X_localXunionXoutE_count__inE_count__outE_weight_sumXX': [(lambda g, vid2=None,vid1=None:g.V(vid1,vid2).local(__.union(__.outE().count(),__.inE().count(),__.outE().weight.sum())))], 
+    'g_VX1_2X_localXunionXcountXX': [(lambda g, vid2=None,vid1=None:g.V(vid1,vid2).local(__.union(__.count())))], 
+    'g_V_andXhasXage_gt_27X__outE_count_gte_2X_name': [(lambda g:g.V().and_(__.has('age',P.gt(27)),__.outE().count().is_(P.gte(2))).name)], 
+    'g_V_andXoutE__hasXlabel_personX_and_hasXage_gte_32XX_name': [(lambda g:g.V().and_(__.outE(),__.has(T.label,'person').and_().has('age',P.gte(32))).name)], 
+    'g_V_asXaX_outXknowsX_and_outXcreatedX_inXcreatedX_asXaX_name': [(lambda g:g.V().as_('a').out('knows').and_().out('created').in_('created').as_('a').name)], 
+    'g_V_asXaX_andXselectXaX_selectXaXX': [(lambda g:g.V().as_('a').and_(__.select('a'),__.select('a')))], 
+    'g_V_hasXname_markoX_and_hasXname_markoX_and_hasXname_markoX': [(lambda g:g.V().has('name','marko').and_().has('name','marko').and_().has('name','marko'))], 
+    'g_V_coinX1X': [(lambda g:g.V().coin(float(1.0)))], 
+    'g_V_coinX0X': [(lambda g:g.V().coin(float(0.0)))], 
+    'g_VX1X_outXcreatedX_inXcreatedX_cyclicPath': [(lambda g, vid1=None:g.V(vid1).out('created').in_('created').cyclicPath())], 
+    'g_VX1X_outXcreatedX_inXcreatedX_cyclicPath_path': [(lambda g, vid1=None:g.V(vid1).out('created').in_('created').cyclicPath().path())], 
+    'g_VX1X_asXaX_outXcreatedX_asXbX_inXcreatedX_asXcX_cyclicPath_fromXaX_toXbX_path': [(lambda g, vid1=None:g.V(vid1).as_('a').out('created').as_('b').in_('created').as_('c').cyclicPath().from_('a').to('b').path())], 
+    'g_V_out_in_valuesXnameX_fold_dedupXlocalX_unfold': [(lambda g:g.V().out().in_().name.fold().dedup(Scope.local).unfold())], 
+    'g_V_out_asXxX_in_asXyX_selectXx_yX_byXnameX_fold_dedupXlocal_x_yX_unfold': [(lambda g:g.V().out().as_('x').in_().as_('y').select('x','y').by('name').fold().dedup(Scope.local,'x','y').unfold())], 
+    'g_V_both_dedup_name': [(lambda g:g.V().both().dedup().name)], 
+    'g_V_both_hasXlabel_softwareX_dedup_byXlangX_name': [(lambda g:g.V().both().has(T.label,'software').dedup().by('lang').name)], 
+    'g_V_both_name_order_byXa_bX_dedup_value': [(lambda g, c1=None:g.V().both().properties('name').order().by(c1).dedup().value())], 
+    'g_V_both_both_name_dedup': [(lambda g:g.V().both().both().name.dedup())], 
+    'g_V_both_both_dedup': [(lambda g:g.V().both().both().dedup())], 
+    'g_V_both_both_dedup_byXlabelX': [(lambda g:g.V().both().both().dedup().by(T.label))], 
+    'g_V_group_byXlabelX_byXbothE_weight_dedup_foldX': [(lambda g:g.V().group().by(T.label).by(__.bothE().weight.dedup().fold()))], 
+    'g_V_asXaX_both_asXbX_dedupXa_bX_byXlabelX_selectXa_bX': [(lambda g:g.V().as_('a').both().as_('b').dedup('a','b').by(T.label).select('a','b'))], 
+    'g_V_asXaX_outXcreatedX_asXbX_inXcreatedX_asXcX_dedupXa_bX_path': [(lambda g:g.V().as_('a').out('created').as_('b').in_('created').as_('c').dedup('a','b').path())], 
+    'g_V_outE_asXeX_inV_asXvX_selectXeX_order_byXweight_ascX_selectXvX_valuesXnameX_dedup': [(lambda g:g.V().outE().as_('e').inV().as_('v').select('e').order().by('weight',Order.asc).select('v').name.dedup())], 
+    'g_V_both_both_dedup_byXoutE_countX_name': [(lambda g:g.V().both().both().dedup().by(__.outE().count()).name)], 
+    'g_V_groupCount_selectXvaluesX_unfold_dedup': [(lambda g:g.V().groupCount().select(Column.values).unfold().dedup())], 
+    'g_V_asXaX_repeatXbothX_timesX3X_emit_name_asXbX_group_byXselectXaXX_byXselectXbX_dedup_order_foldX_selectXvaluesX_unfold_dedup': [(lambda g:g.V().as_('a').repeat(__.both()).times(3).emit().name.as_('b').group().by(__.select('a')).by(__.select('b').dedup().order().fold()).select(Column.values).unfold().dedup())], 
+    'g_V_repeatXdedupX_timesX2X_count': [(lambda g:g.V().repeat(__.dedup()).times(2).count())], 
+    'g_V_both_group_by_byXout_dedup_foldX_unfold_selectXvaluesX_unfold_out_order_byXnameX_limitX1X_valuesXnameX': [(lambda g:g.V().both().group().by().by(__.out().dedup().fold()).unfold().select(Column.values).unfold().out().order().by('name')[0:1].name)], 
+    'g_V_bothE_properties_dedup_count': [(lambda g:g.V().bothE().properties().dedup().count())], 
+    'g_V_both_properties_dedup_count': [(lambda g:g.V().both().properties().dedup().count())], 
+    'g_V_both_properties_properties_dedup_count': [(lambda g:g.V().both().properties().properties().dedup().count())], 
+    'g_V_drop': [(lambda g:g.addV().as_('a').addV().as_('b').addE('knows').to('a')), (lambda g:g.V().drop()), (lambda g:g.V()), (lambda g:g.E())], 
+    'g_V_outE_drop': [(lambda g:g.addV().as_('a').addV().as_('b').addE('knows').to('a')), (lambda g:g.V().outE().drop()), (lambda g:g.V()), (lambda g:g.E())], 
+    'g_V_properties_drop': [(lambda g:g.addV().property('name','bob').addV().property('name','alice')), (lambda g:g.V().properties().drop()), (lambda g:g.V()), (lambda g:g.V().properties())], 
+    'g_E_propertiesXweightX_drop': [(lambda g:g.addV('person').property(T.id,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id,5).property('name','ripple').property('lang','java').as_('ripple').addV('person').property(T.id,6).property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property(T.id,7).property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property(T.id,8).property('weight',float(1.0)).addE('created').from_('marko').to('lop').property(T.id,9).property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property(T.id,10).property('weight',float(1.0)).addE('created').from_('josh').to('lop').property(T.id,11).property('weight',float(0.4)).addE('created').from_('peter').to('lop').property(T.id,12).property('weight',float(0.2))), (lambda g:g.E().properties('weight').drop()), (lambda g:g.E().properties())], 
+    'g_V_properties_propertiesXstartTimeX_drop': [(lambda g:g.addV().property('name','bob').property(Cardinality.list_,'location','ny','startTime',2014,'endTime',2016).property(Cardinality.list_,'location','va','startTime',2016).addV().property('name','alice').property(Cardinality.list_,'location','va','startTime',2014,'endTime',2016).property(Cardinality.list_,'location','ny','startTime',2016)), (lambda g:g.V().properties().properties('startTime').drop()), (lambda g:g.V().properties().properties()), (lambda g:g.V().properties().properties('startTime'))], 
+    'g_V_filterXfalseX': [(lambda g, pred1=None:g.V().filter(pred1))], 
+    'g_V_filterXtrueX': [(lambda g, pred1=None:g.V().filter(pred1))], 
+    'g_V_filterXlang_eq_javaX': [(lambda g, pred1=None:g.V().filter(pred1))], 
+    'g_VX1X_filterXage_gt_30X': [(lambda g, vid1=None,pred1=None:g.V(vid1).filter(pred1))], 
+    'g_VX2X_filterXage_gt_30X': [(lambda g, vid2=None,pred1=None:g.V(vid2).filter(pred1))], 
+    'g_VX1X_out_filterXage_gt_30X': [(lambda g, vid1=None,pred1=None:g.V(vid1).out().filter(pred1))], 
+    'g_V_filterXname_startsWith_m_OR_name_startsWith_pX': [(lambda g, pred1=None:g.V().filter(pred1))], 
+    'g_E_filterXfalseX': [(lambda g, pred1=None:g.E().filter(pred1))], 
+    'g_E_filterXtrueX': [(lambda g, pred1=None:g.E().filter(pred1))], 
+    'g_V_outXcreatedX_hasXname__mapXlengthX_isXgtX3XXX_name': [(lambda g, l1=None:g.V().out('created').has('name',__.map(l1).is_(P.gt(3))).name)], 
+    'g_VX1X_hasXnameX': [(lambda g, vid1=None:g.V(vid1).has('name'))], 
+    'g_VX1X_hasXcircumferenceX': [(lambda g, vid1=None:g.V(vid1).has('circumference'))], 
+    'g_VX1X_hasXname_markoX': [(lambda g, vid1=None:g.V(vid1).has('name','marko'))], 
+    'g_VX2X_hasXname_markoX': [(lambda g, vid1=None:g.V(vid1).has('name','marko'))], 
+    'g_V_hasXname_markoX': [(lambda g:g.V().has('name','marko'))], 
+    'g_V_hasXname_blahX': [(lambda g:g.V().has('name','blah'))], 
+    'g_V_hasXage_gt_30X': [(lambda g:g.V().has('age',P.gt(30)))], 
+    'g_V_hasXage_isXgt_30XX': [(lambda g:g.V().has('age',__.is_(P.gt(30))))], 
+    'g_V_hasXlabel_isXsoftwareXX': [(lambda g:g.V().has(T.label,__.is_('software')))], 
+    'g_VX1X_hasXage_gt_30X': [(lambda g, vid1=None:g.V(vid1).has('age',P.gt(30)))], 
+    'g_VX4X_hasXage_gt_30X': [(lambda g, vid4=None:g.V(vid4).has('age',P.gt(30)))], 
+    'g_VXv1X_hasXage_gt_30X': [(lambda g, v1=None:g.V(v1).has('age',P.gt(30)))], 
+    'g_VXv4X_hasXage_gt_30X': [(lambda g, v4=None:g.V(v4).has('age',P.gt(30)))], 
+    'g_VX1X_out_hasXid_lt_3X': [(lambda g, xx1=None,vid1=None:g.V(vid1).out().has(T.id,xx1))], 
+    'g_VX1AsStringX_out_hasXid_2AsStringX': [(lambda g, vid2=None,vid1=None:g.V(vid1).out().hasId(vid2))], 
+    'g_VX1X_out_hasXid_2X': [(lambda g, v2=None:g.V(v2).has('age',P.gt(30)))], 
+    'g_VX1X_out_hasIdX2X': [(lambda g, vid2=None,vid1=None:g.V(vid1).out().hasId(vid2))], 
+    'g_VX1X_out_hasXid_2_3X': [(lambda g, vid3=None,vid2=None,vid1=None:g.V(vid1).out().hasId(vid2,vid3))], 
+    'g_VX1X_out_hasXid_2AsString_3AsStringX': [(lambda g, vid3=None,vid2=None,vid1=None:g.V(vid1).out().hasId(vid2,vid3))], 
+    'g_V_hasXblahX': [(lambda g:g.V().has('blah'))], 
+    'g_EX7X_hasXlabelXknowsX': [(lambda g, eid7=None:g.E(eid7).hasLabel('knows'))], 
+    'g_E_hasXlabelXknowsX': [(lambda g:g.E().hasLabel('knows'))], 
+    'g_E_hasLabelXuses_traversesX': [(lambda g:g.E().hasLabel('uses','traverses'))], 
+    'g_V_hasLabelXperson_software_blahX': [(lambda g:g.V().hasLabel('person','software','blah'))], 
+    'g_V_hasXperson_name_markoX_age': [(lambda g:g.V().has('person','name','marko').age)], 
+    'g_VX1X_outE_hasXweight_inside_0_06X_inV': [(lambda g, vid1=None:g.V(vid1).outE().has('weight',P.gt(float(0.0)).and_(P.lt(float(0.6)))).inV())], 
+    'g_EX11X_outV_outE_hasXid_10X': [(lambda g, eid11=None,eid10=None:g.E(eid11).outV().outE().has(T.id,eid10))], 
+    'g_EX11X_outV_outE_hasXid_10AsStringX': [(lambda g, eid11=None,eid10=None:g.E(eid11).outV().outE().has(T.id,eid10))], 
+    'g_V_hasXlocationX': [(lambda g:g.V().has('location'))], 
+    'g_V_hasLabelXpersonX_hasXage_notXlteX10X_andXnotXbetweenX11_20XXXX_andXltX29X_orXeqX35XXXX_name': [(lambda g:g.V().hasLabel('person').has('age',P.gt(10).or_(P.gte(11).and_(P.lt(20))).and_(P.lt(29).or_(P.eq(35)))).name)], 
+    'g_V_in_hasIdXneqX1XX': [(lambda g, xx1=None:g.V().in_().hasId(xx1))], 
+    'g_V_hasXage_withinX27X_count': [(lambda g:g.V().has('age',P.within([27])).count())], 
+    'g_V_hasXage_withinX27_29X_count': [(lambda g:g.V().has('age',P.within([27,29])).count())], 
+    'g_V_hasXage_withoutX27X_count': [(lambda g:g.V().has('age',P.without([27])).count())], 
+    'g_V_hasXage_withoutX27_29X_count': [(lambda g:g.V().has('age',P.without([27,29])).count())], 
+    'g_V_both_dedup_properties_hasKeyXageX_value': [(lambda g:g.V().both().properties().dedup().hasKey('age').value())], 
+    'g_V_both_dedup_properties_hasKeyXageX_hasValueXgtX30XX_value': [(lambda g:g.V().both().properties().dedup().hasKey('age').hasValue(P.gt(30)).value())], 
+    'g_V_bothE_properties_dedup_hasKeyXweightX_value': [(lambda g:g.V().bothE().properties().dedup().hasKey('weight').value())], 
+    'g_V_bothE_properties_dedup_hasKeyXweightX_hasValueXltX0d3XX_value': [(lambda g:g.V().bothE().properties().dedup().hasKey('weight').hasValue(P.lt(float(0.3))).value())], 
+    'g_V_hasNotXageX_name': [(lambda g:g.V().hasNot('age').name)], 
+    'g_V_hasIdX1X_hasIdX2X': [(lambda g, vid2=None,vid1=None:g.V().hasId(vid1).hasId(vid2))], 
+    'g_V_hasLabelXpersonX_hasLabelXsoftwareX': [(lambda g:g.V().hasLabel('person').hasLabel('software'))], 
+    'g_V_hasIdXemptyX_count': [(lambda g, xx1=None:g.V().hasId(xx1).count())], 
+    'g_V_hasIdXwithinXemptyXX_count': [(lambda g, xx1=None:g.V().hasId(xx1).count())], 
+    'g_V_hasIdXwithoutXemptyXX_count': [(lambda g, xx1=None:g.V().hasId(xx1).count())], 
+    'g_V_notXhasIdXwithinXemptyXXX_count': [(lambda g, xx1=None:g.V().not_(__.hasId(xx1)).count())], 
+    'g_V_hasXname_containingXarkXX': [(lambda g:g.V().has('name',TextP.containing('ark')))], 
+    'g_V_hasXname_startingWithXmarXX': [(lambda g:g.V().has('name',TextP.startingWith('mar')))], 
+    'g_V_hasXname_endingWithXasXX': [(lambda g:g.V().has('name',TextP.endingWith('as')))], 
+    'g_V_hasXperson_name_containingXoX_andXltXmXXX': [(lambda g:g.V().has('person','name',TextP.containing('o').and_(P.lt('m'))))], 
+    'g_V_hasXname_gtXmX_andXcontainingXoXXX': [(lambda g:g.V().has('name',P.gt('m').and_(TextP.containing('o'))))], 
+    'g_V_hasXname_not_containingXarkXX': [(lambda g:g.V().has('name',TextP.notContaining('ark')))], 
+    'g_V_hasXname_not_startingWithXmarXX': [(lambda g:g.V().has('name',TextP.notStartingWith('mar')))], 
+    'g_V_hasXname_not_endingWithXasXX': [(lambda g:g.V().has('name',TextP.notEndingWith('as')))], 
+    'g_V_hasXp_neqXvXX': [(lambda g:g.V().has('p',P.neq('v')))], 
+    'g_V_hasXage_gtX18X_andXltX30XXorXgtx35XXX': [(lambda g:g.V().has('age',P.gt(18).and_(P.lt(30)).or_(P.gt(35))))], 
+    'g_V_hasXage_gtX18X_andXltX30XXorXltx35XXX': [(lambda g:g.V().has('age',P.gt(18).and_(P.lt(30)).and_(P.lt(35))))], 
+    'g_V_valuesXageX_isX32X': [(lambda g:g.V().age.is_(32))], 
+    'g_V_valuesXageX_isXlte_30X': [(lambda g:g.V().age.is_(P.lte(30)))], 
+    'g_V_valuesXageX_isXgte_29X_isXlt_34X': [(lambda g:g.V().age.is_(P.gte(29)).is_(P.lt(34)))], 
+    'g_V_whereXinXcreatedX_count_isX1XX_valuesXnameX': [(lambda g:g.V().where(__.in_('created').count().is_(1)).name)], 
+    'g_V_whereXinXcreatedX_count_isXgte_2XX_valuesXnameX': [(lambda g:g.V().where(__.in_('created').count().is_(P.gte(2))).name)], 
+    'g_V_orXhasXage_gt_27X__outE_count_gte_2X_name': [(lambda g:g.V().or_(__.has('age',P.gt(27)),__.outE().count().is_(P.gte(2))).name)], 
+    'g_V_orXoutEXknowsX__hasXlabel_softwareX_or_hasXage_gte_35XX_name': [(lambda g:g.V().or_(__.outE('knows'),__.has(T.label,'software').or_().has('age',P.gte(35))).name)], 
+    'g_V_asXaX_orXselectXaX_selectXaXX': [(lambda g:g.V().as_('a').or_(__.select('a'),__.select('a')))], 
+    'g_VX1X_out_limitX2X': [(lambda g, vid1=None:g.V(vid1).out()[0:2])], 
+    'g_V_localXoutE_limitX1X_inVX_limitX3X': [(lambda g:g.V().local(__.outE()[0:1]).inV()[0:3])], 
+    'g_VX1X_outXknowsX_outEXcreatedX_rangeX0_1X_inV': [(lambda g, vid1=None:g.V(vid1).out('knows').outE('created')[0].inV())], 
+    'g_VX1X_outXknowsX_outXcreatedX_rangeX0_1X': [(lambda g, vid1=None:g.V(vid1).out('knows').out('created')[0])], 
+    'g_VX1X_outXcreatedX_inXcreatedX_rangeX1_3X': [(lambda g, vid1=None:g.V(vid1).out('created').in_('created')[1:3])], 
+    'g_VX1X_outXcreatedX_inEXcreatedX_rangeX1_3X_outV': [(lambda g, vid1=None:g.V(vid1).out('created').inE('created')[1:3].outV())], 
+    'g_V_repeatXbothX_timesX3X_rangeX5_11X': [(lambda g:g.V().repeat(__.both()).times(3)[5:11])], 
+    'g_V_asXaX_in_asXbX_in_asXcX_selectXa_b_cX_byXnameX_limitXlocal_2X': [(lambda g:g.V().as_('a').in_().as_('b').in_().as_('c').select('a','b','c').by('name').limit(Scope.local,2))], 
+    'g_V_asXaX_in_asXbX_in_asXcX_selectXa_b_cX_byXnameX_limitXlocal_1X': [(lambda g:g.V().as_('a').in_().as_('b').in_().as_('c').select('a','b','c').by('name').limit(Scope.local,1))], 
+    'g_V_asXaX_out_asXbX_out_asXcX_selectXa_b_cX_byXnameX_rangeXlocal_1_3X': [(lambda g:g.V().as_('a').out().as_('b').out().as_('c').select('a','b','c').by('name').range(Scope.local,1,3))], 
+    'g_V_asXaX_out_asXbX_out_asXcX_selectXa_b_cX_byXnameX_rangeXlocal_1_2X': [(lambda g:g.V().as_('a').out().as_('b').out().as_('c').select('a','b','c').by('name').range(Scope.local,1,2))], 
+    'g_V_asXaX_out_asXaX_out_asXaX_selectXmixed_aX_byXunfold_valuesXnameX_foldX_rangeXlocal_1_3X': [(lambda g:g.V().as_('a').out().as_('a').out().as_('a').select(Pop.mixed,'a').by(__.unfold().name.fold()).range(Scope.local,1,3))], 
+    'g_V_asXaX_out_asXaX_out_asXaX_selectXmixed_aX_byXunfold_valuesXnameX_foldX_rangeXlocal_1_2X': [(lambda g:g.V().as_('a').out().as_('a').out().as_('a').select(Pop.mixed,'a').by(__.unfold().name.fold()).range(Scope.local,1,2))], 
+    'g_V_hasLabelXpersonX_order_byXageX_skipX1X_valuesXnameX': [(lambda g:g.V().hasLabel('person').order().by('age').skip(1).name)], 
+    'g_V_asXaX_out_asXaX_out_asXaX_selectXmixed_aX_byXunfold_valuesXnameX_foldX_rangeXlocal_4_5X': [(lambda g:g.V().as_('a').out().as_('a').out().as_('a').select(Pop.mixed,'a').by(__.unfold().name.fold()).range(Scope.local,4,5))], 
+    'g_V_outE_valuesXweightX_fold_orderXlocalX_skipXlocal_2X': [(lambda g:g.V().outE().weight.fold().order(Scope.local).skip(Scope.local,2))], 
+    'g_V_asXaX_in_asXaX_in_asXaX_selectXmixed_aX_byXunfold_valuesXnameX_foldX_limitXlocal_1X': [(lambda g:g.V().as_('a').in_().as_('a').in_().as_('a').select(Pop.mixed,'a').by(__.unfold().name.fold()).limit(Scope.local,1))], 
+    'g_V_asXaX_in_asXaX_in_asXaX_selectXmixed_aX_byXunfold_valuesXnameX_foldX_limitXlocal_2X': [(lambda g:g.V().as_('a').in_().as_('a').in_().as_('a').select(Pop.mixed,'a').by(__.unfold().name.fold()).limit(Scope.local,2))], 
+    'g_V_hasLabelXpersonX_order_byXageX_valuesXnameX_skipX1X': [(lambda g:g.V().hasLabel('person').order().by('age').name.skip(1))], 
+    'g_E_sampleX1X': [(lambda g:g.E().sample(1))], 
+    'g_E_sampleX2X_byXweightX': [(lambda g:g.E().sample(2).by('weight'))], 
+    'g_V_localXoutE_sampleX1X_byXweightXX': [(lambda g:g.V().local(__.outE().sample(1).by('weight')))], 
+    'g_V_group_byXlabelX_byXbothE_weight_sampleX2X_foldX': [(lambda g:g.V().group().by(T.label).by(__.bothE().weight.sample(2).fold()))], 
+    'g_V_group_byXlabelX_byXbothE_weight_fold_sampleXlocal_5XX': [(lambda g:g.V().group().by(T.label).by(__.bothE().weight.fold().sample(Scope.local,5)))], 
+    'g_VX1X_outXcreatedX_inXcreatedX_simplePath': [(lambda g, vid1=None:g.V(vid1).out('created').in_('created').simplePath())], 
+    'g_V_repeatXboth_simplePathX_timesX3X_path': [(lambda g:g.V().repeat(__.both().simplePath()).times(3).path())], 
+    'g_V_asXaX_out_asXbX_out_asXcX_simplePath_byXlabelX_fromXbX_toXcX_path_byXnameX': [(lambda g:g.V().as_('a').out().as_('b').out().as_('c').simplePath().by(T.label).from_('b').to('c').path().by('name'))], 
+    'g_V_valuesXnameX_order_tailXglobal_2X': [(lambda g:g.V().name.order().tail(Scope.global_,2))], 
+    'g_V_valuesXnameX_order_tailX2X': [(lambda g:g.V().name.order().tail(2))], 
+    'g_V_valuesXnameX_order_tail': [(lambda g:g.V().name.order().tail())], 
+    'g_V_valuesXnameX_order_tailX7X': [(lambda g:g.V().name.order().tail(7))], 
+    'g_V_repeatXbothX_timesX3X_tailX7X': [(lambda g:g.V().repeat(__.both()).times(3).tail(7))], 
+    'g_V_repeatXin_outX_timesX3X_tailX7X_count': [(lambda g:g.V().repeat(__.in_().out()).times(3).tail(7).count())], 
+    'g_V_asXaX_out_asXaX_out_asXaX_selectXaX_byXunfold_valuesXnameX_foldX_tailXlocal_1X': [(lambda g:g.V().as_('a').out().as_('a').out().as_('a').select('a').by(__.unfold().name.fold()).tail(Scope.local,1))], 
+    'g_V_asXaX_out_asXaX_out_asXaX_selectXaX_byXunfold_valuesXnameX_foldX_tailXlocalX': [(lambda g:g.V().as_('a').out().as_('a').out().as_('a').select('a').by(__.unfold().name.fold()).tail(Scope.local))], 
+    'g_V_asXaX_out_asXbX_out_asXcX_selectXa_b_cX_byXnameX_tailXlocal_2X': [(lambda g:g.V().as_('a').out().as_('b').out().as_('c').select('a','b','c').by('name').tail(Scope.local,2))], 
+    'g_V_asXaX_out_asXbX_out_asXcX_selectXa_b_cX_byXnameX_tailXlocal_1X': [(lambda g:g.V().as_('a').out().as_('b').out().as_('c').select('a','b','c').by('name').tail(Scope.local,1))], 
+    'g_V_asXaX_out_asXaX_out_asXaX_selectXmixed_aX_byXunfold_valuesXnameX_foldX_tailXlocal_1X': [(lambda g:g.V().as_('a').out().as_('a').out().as_('a').select(Pop.mixed,'a').by(__.unfold().name.fold()).tail(Scope.local,1))], 
+    'g_V_asXaX_out_asXaX_out_asXaX_selectXmixed_aX_byXunfold_valuesXnameX_foldX_tailXlocalX': [(lambda g:g.V().as_('a').out().as_('a').out().as_('a').select(Pop.mixed,'a').by(__.unfold().name.fold()).tail(Scope.local))], 
+    'g_V_asXaX_out_asXaX_out_asXaX_selectXmixed_aX_byXlimitXlocal_0XX_tailXlocal_1X': [(lambda g:g.V().as_('a').out().as_('a').out().as_('a').select(Pop.mixed,'a').by(__.limit(Scope.local,0)).tail(Scope.local,1))], 
+    'g_V_asXaX_out_asXaX_out_asXaX_selectXmixed_aX_byXunfold_valuesXnameX_foldX_tailXlocal_2X': [(lambda g:g.V().as_('a').out().as_('a').out().as_('a').select(Pop.mixed,'a').by(__.unfold().name.fold()).tail(Scope.local,2))], 
+    'g_V_hasXageX_asXaX_out_in_hasXageX_asXbX_selectXa_bX_whereXa_eqXbXX': [(lambda g:g.V().has('age').as_('a').out().in_().has('age').as_('b').select('a','b').where('a',P.eq('b')))], 
+    'g_V_hasXageX_asXaX_out_in_hasXageX_asXbX_selectXa_bX_whereXa_neqXbXX': [(lambda g:g.V().has('age').as_('a').out().in_().has('age').as_('b').select('a','b').where('a',P.neq('b')))], 
+    'g_V_hasXageX_asXaX_out_in_hasXageX_asXbX_selectXa_bX_whereXb_hasXname_markoXX': [(lambda g:g.V().has('age').as_('a').out().in_().has('age').as_('b').select('a','b').where(__.as_('b').has('name','marko')))], 
+    'g_V_hasXageX_asXaX_out_in_hasXageX_asXbX_selectXa_bX_whereXa_outXknowsX_bX': [(lambda g:g.V().has('age').as_('a').out().in_().has('age').as_('b').select('a','b').where(__.as_('a').out('knows').as_('b')))], 
+    'g_V_asXaX_outXcreatedX_whereXasXaX_name_isXjoshXX_inXcreatedX_name': [(lambda g:g.V().as_('a').out('created').where(__.as_('a').name.is_('josh')).in_('created').name)], 
+    'g_withSideEffectXa_josh_peterX_VX1X_outXcreatedX_inXcreatedX_name_whereXwithinXaXX': [(lambda g, xx1=None,vid1=None:g.withSideEffect('a',xx1).V(vid1).out('created').in_('created').name.where(P.within(['a'])))], 
+    'g_VX1X_asXaX_outXcreatedX_inXcreatedX_asXbX_whereXa_neqXbXX_name': [(lambda g, vid1=None:g.V(vid1).as_('a').out('created').in_('created').as_('b').where('a',P.neq('b')).name)], 
+    'g_VX1X_asXaX_outXcreatedX_inXcreatedX_asXbX_whereXasXbX_outXcreatedX_hasXname_rippleXX_valuesXage_nameX': [(lambda g, vid1=None:g.V(vid1).as_('a').out('created').in_('created').as_('b').where(__.as_('b').out('created').has('name','ripple')).values('age','name'))], 
+    'g_VX1X_asXaX_outXcreatedX_inXcreatedX_whereXeqXaXX_name': [(lambda g, vid1=None:g.V(vid1).as_('a').out('created').in_('created').where(P.eq('a')).name)], 
+    'g_VX1X_asXaX_outXcreatedX_inXcreatedX_whereXneqXaXX_name': [(lambda g, vid1=None:g.V(vid1).as_('a').out('created').in_('created').where(P.neq('a')).name)], 
+    'g_VX1X_out_aggregateXxX_out_whereXnotXwithinXaXXX': [(lambda g, vid1=None:g.V(vid1).out().aggregate('x').out().where(P.without(['x'])))], 
+    'g_withSideEffectXa_g_VX2XX_VX1X_out_whereXneqXaXX': [(lambda g, vid1=None,v2=None:g.withSideEffect('a',v2).V(vid1).out().where(P.neq('a')))], 
+    'g_VX1X_repeatXbothEXcreatedX_whereXwithoutXeXX_aggregateXeX_otherVX_emit_path': [(lambda g, vid1=None:g.V(vid1).repeat(__.bothE('created').where(P.without(['e'])).aggregate('e').otherV()).emit().path())], 
+    'g_V_whereXnotXoutXcreatedXXX_name': [(lambda g:g.V().where(__.not_(__.out('created'))).name)], 
+    'g_V_asXaX_out_asXbX_whereXandXasXaX_outXknowsX_asXbX__orXasXbX_outXcreatedX_hasXname_rippleX__asXbX_inXknowsX_count_isXnotXeqX0XXXXX_selectXa_bX': [(lambda g:g.V().as_('a').out().as_('b').where(__.and_(__.as_('a').out('knows').as_('b'),__.or_(__.as_('b').out('created').has('name','ripple'),__.as_('b').in_('knows').count().is_(P.neq(0))))).select('a','b'))], 
+    'g_V_whereXoutXcreatedX_and_outXknowsX_or_inXknowsXX_valuesXnameX': [(lambda g:g.V().where(__.out('created').and_().out('knows').or_().in_('knows')).name)], 
+    'g_V_asXaX_outXcreatedX_asXbX_whereXandXasXbX_in__notXasXaX_outXcreatedX_hasXname_rippleXXX_selectXa_bX': [(lambda g:g.V().as_('a').out('created').as_('b').where(__.and_(__.as_('b').in_(),__.not_(__.as_('a').out('created').has('name','ripple')))).select('a','b'))], 
+    'g_V_asXaX_outXcreatedX_asXbX_inXcreatedX_asXcX_bothXknowsX_bothXknowsX_asXdX_whereXc__notXeqXaX_orXeqXdXXXX_selectXa_b_c_dX': [(lambda g:g.V().as_('a').out('created').as_('b').in_('created').as_('c').both('knows').both('knows').as_('d').where('c',P.neq('a').and_(P.neq('d'))).select('a','b','c','d'))], 
+    'g_V_asXaX_out_asXbX_whereXin_count_isXeqX3XX_or_whereXoutXcreatedX_and_hasXlabel_personXXX_selectXa_bX': [(lambda g:g.V().as_('a').out().as_('b').where(__.as_('b').in_().count().is_(P.eq(3)).or_().where(__.as_('b').out('created').and_().as_('b').has(T.label,'person'))).select('a','b'))], 
+    'g_V_asXaX_outXcreatedX_inXcreatedX_asXbX_whereXa_gtXbXX_byXageX_selectXa_bX_byXnameX': [(lambda g:g.V().as_('a').out('created').in_('created').as_('b').where('a',P.gt('b')).by('age').select('a','b').by('name'))], 
+    'g_V_asXaX_outEXcreatedX_asXbX_inV_asXcX_whereXa_gtXbX_orXeqXbXXX_byXageX_byXweightX_byXweightX_selectXa_cX_byXnameX': [(lambda g:g.V().as_('a').outE('created').as_('b').inV().as_('c').where('a',P.gt('b').or_(P.eq('b'))).by('age').by('weight').by('weight').select('a','c').by('name'))], 
+    'g_V_asXaX_outEXcreatedX_asXbX_inV_asXcX_inXcreatedX_asXdX_whereXa_ltXbX_orXgtXcXX_andXneqXdXXX_byXageX_byXweightX_byXinXcreatedX_valuesXageX_minX_selectXa_c_dX': [(lambda g:g.V().as_('a').outE('created').as_('b').inV().as_('c').in_('created').as_('d').where('a',P.lt('b').or_(P.gt('c')).and_(P.neq('d'))).by('age').by('weight').by(__.in_('created').age.min()).select('a','c','d').by('name'))], 
+    'g_VX1X_asXaX_out_hasXageX_whereXgtXaXX_byXageX_name': [(lambda g, vid1=None:g.V(vid1).as_('a').out().has('age').where(P.gt('a')).by('age').name)], 
+    'g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX': [(lambda g, vid1=None:g.addV('person').property(T.id,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id,5).property('name','ripple').property('lang','java').as_('ripple').addV('person').property(T.id,6).property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property(T.id,7).property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property(T.id,8).property('weight',float(1.0)).addE('created').from_('marko').to('lop').property(T.id,9).property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property(T.id,10).property('weight',float(1.0)).addE('created').from_('josh').to('lop').property(T.id,11).property('weight',float(0.4)).addE('created').from_('peter').to('lop').property(T.id,12).property('weight',float(0.2))), (lambda g, vid1=None:g.V(vid1).as_('a').out('created').addE('createdBy').to('a')), (lambda g, vid1=None:g.E()), (lambda g, vid1=None:g.V(vid1).inE())], 
+    'g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX_propertyXweight_2X': [(lambda g, vid1=None:g.addV('person').property(T.id,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id,5).property('name','ripple').property('lang','java').as_('ripple').addV('person').property(T.id,6).property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property(T.id,7).property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property(T.id,8).property('weight',float(1.0)).addE('created').from_('marko').to('lop').property(T.id,9).property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property(T.id,10).property('weight',float(1.0)).addE('created').from_('josh').to('lop').property(T.id,11).property('weight',float(0.4)).addE('created').from_('peter').to('lop').property(T.id,12).property('weight',float(0.2))), (lambda g, vid1=None:g.V(vid1).as_('a').out('created').addE('createdBy').to('a').property('weight',float(2.0))), (lambda g, vid1=None:g.E()), (lambda g, vid1=None:g.V(vid1).bothE()), (lambda g, vid1=None:g.V(vid1).inE().has('weight',float(2.0)))], 
+    'g_V_outE_propertyXweight_nullX': [(lambda g:g.addV('person').property(T.id,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id,5).property('name','ripple').property('lang','java').as_('ripple').addV('person').property(T.id,6).property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property(T.id,7).property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property(T.id,8).property('weight',float(1.0)).addE('created').from_('marko').to('lop').property(T.id,9).property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property(T.id,10).property('weight',float(1.0)).addE('created').from_('josh').to('lop').property(T.id,11).property('weight',float(0.4)).addE('created').from_('peter').to('lop').property(T.id,12).property('weight',float(0.2))), (lambda g:g.V().outE().property('weight',None)), (lambda g:g.E().properties('weight'))], 
+    'g_V_aggregateXxX_asXaX_selectXxX_unfold_addEXexistsWithX_toXaX_propertyXtime_nowX': [(lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.addV('person').property(T.id,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id,5).property('name','ripple').property('lang','java').as_('ripple').addV('person').property(T.id,6).property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property(T.id,7).property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property(T.id,8).property('weight',float(1.0)).addE('created').from_('marko').to('lop').property(T.id,9).property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property(T.id,10).property('weight',float(1.0)).addE('created').from_('josh').to('lop').property(T.id,11).property('weight',float(0.4)).addE('created').from_('peter').to('lop').property(T.id,12).property('weight',float(0.2))), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V().aggregate('x').as_('a').select('x').unfold().addE('existsWith').to('a').property('time','now')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.E()), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid1).bothE()), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid1).inE('existsWith')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid1).outE('existsWith')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid1).bothE('existsWith').has('time','now')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid2).bothE()), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid2).inE('existsWith')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid2).outE('existsWith')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid2).bothE('existsWith').has('time','now')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid3).bothE()), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid3).inE('existsWith')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid3).outE('existsWith')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid3).bothE('existsWith').has('time','now')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid4).bothE()), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid4).inE('existsWith')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid4).outE('existsWith')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid4).bothE('existsWith').has('time','now')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid5).bothE()), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid5).inE('existsWith')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid5).outE('existsWith')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid5).bothE('existsWith').has('time','now')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid6).bothE()), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid6).inE('existsWith')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid6).outE('existsWith')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid6).bothE('existsWith').has('time','now'))], 
+    'g_V_asXaX_outXcreatedX_inXcreatedX_whereXneqXaXX_asXbX_addEXcodeveloperX_fromXaX_toXbX_propertyXyear_2009X': [(lambda g, vid1=None,vid2=None,vid4=None,vid6=None:g.addV('person').property(T.id,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id,5).property('name','ripple').property('lang','java').as_('ripple').addV('person').property(T.id,6).property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property(T.id,7).property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property(T.id,8).property('weight',float(1.0)).addE('created').from_('marko').to('lop').property(T.id,9).property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property(T.id,10).property('weight',float(1.0)).addE('created').from_('josh').to('lop').property(T.id,11).property('weight',float(0.4)).addE('created').from_('peter').to('lop').property(T.id,12).property('weight',float(0.2))), (lambda g, vid1=None,vid2=None,vid4=None,vid6=None:g.V().as_('a').out('created').in_('created').where(P.neq('a')).as_('b').addE('codeveloper').from_('a').to('b').property('year',2009)), (lambda g, vid1=None,vid2=None,vid4=None,vid6=None:g.E()), (lambda g, vid1=None,vid2=None,vid4=None,vid6=None:g.V(vid1).bothE()), (lambda g, vid1=None,vid2=None,vid4=None,vid6=None:g.V(vid1).inE('codeveloper')), (lambda g, vid1=None,vid2=None,vid4=None,vid6=None:g.V(vid1).outE('codeveloper')), (lambda g, vid1=None,vid2=None,vid4=None,vid6=None:g.V(vid1).bothE('codeveloper').has('year',2009)), (lambda g, vid1=None,vid2=None,vid4=None,vid6=None:g.V(vid2).bothE()), (lambda g, vid1=None,vid2=None,vid4=None,vid6=None:g.V(vid4).bothE()), (lambda g, vid1=None,vid2=None,vid4=None,vid6=None:g.V(vid4).inE('codeveloper')), (lambda g, vid1=None,vid2=None,vid4=None,vid6=None:g.V(vid4).outE('codeveloper')), (lambda g, vid1=None,vid2=None,vid4=None,vid6=None:g.V(vid4).bothE('codeveloper').has('year',2009)), (lambda g, vid1=None,vid2=None,vid4=None,vid6=None:g.V(vid6).bothE()), (lambda g, vid1=None,vid2=None,vid4=None,vid6=None:g.V(vid6).inE('codeveloper')), (lambda g, vid1=None,vid2=None,vid4=None,vid6=None:g.V(vid6).outE('codeveloper')), (lambda g, vid1=None,vid2=None,vid4=None,vid6=None:g.V(vid6).bothE('codeveloper').has('year',2009))], 
+    'g_V_asXaX_inXcreatedX_addEXcreatedByX_fromXaX_propertyXyear_2009X_propertyXacl_publicX': [(lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.addV('person').property(T.id,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id,5).property('name','ripple').property('lang','java').as_('ripple').addV('person').property(T.id,6).property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property(T.id,7).property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property(T.id,8).property('weight',float(1.0)).addE('created').from_('marko').to('lop').property(T.id,9).property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property(T.id,10).property('weight',float(1.0)).addE('created').from_('josh').to('lop').property(T.id,11).property('weight',float(0.4)).addE('created').from_('peter').to('lop').property(T.id,12).property('weight',float(0.2))), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V().as_('a').in_('created').addE('createdBy').from_('a').property('year',2009).property('acl','public')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.E()), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid1).bothE()), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid1).inE('createdBy')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid1).outE('createdBy')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid1).bothE('createdBy').has('year',2009).has('acl','public')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid2).bothE()), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid3).bothE()), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid3).inE('createdBy')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid3).outE('createdBy')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid3).bothE('createdBy').has('year',2009).has('acl','public')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid4).bothE()), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid4).inE('createdBy')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid4).outE('createdBy')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid4).bothE('createdBy').has('year',2009).has('acl','public')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid5).bothE()), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid5).inE('createdBy')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid5).outE('createdBy')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid5).bothE('createdBy').has('year',2009).has('acl','public')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid6).bothE()), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid6).inE('createdBy')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid6).outE('createdBy')), (lambda g, vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid6).bothE('createdBy').has('year',2009).has('acl','public'))], 
+    'g_withSideEffectXb_bX_VXaX_addEXknowsX_toXbX_propertyXweight_0_5X': [(lambda g, v6=None,v1=None:g.addV('person').property(T.id,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id,5).property('name','ripple').property('lang','java').as_('ripple').addV('person').property(T.id,6).property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property(T.id,7).property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property(T.id,8).property('weight',float(1.0)).addE('created').from_('marko').to('lop').property(T.id,9).property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property(T.id,10).property('weight',float(1.0)).addE('created').from_('josh').to('lop').property(T.id,11).property('weight',float(0.4)).addE('created').from_('peter').to('lop').property(T.id,12).property('weight',float(0.2))), (lambda g, v6=None,v1=None:g.withSideEffect('b',v6).V(v1).addE('knows').to('b').property('weight',float(0.5))), (lambda g, v6=None,v1=None:g.E()), (lambda g, v6=None,v1=None:g.V(v1).bothE()), (lambda g, v6=None,v1=None:g.V(v1).inE('knows')), (lambda g, v6=None,v1=None:g.V(v1).outE('knows')), (lambda g, v6=None,v1=None:g.V(v1).bothE('knows').has('weight',float(0.5))), (lambda g, v6=None,v1=None:g.V(v6).bothE()), (lambda g, v6=None,v1=None:g.V(v6).inE('knows')), (lambda g, v6=None,v1=None:g.V(v6).outE('knows')), (lambda g, v6=None,v1=None:g.V(v6).bothE('knows').has('weight',float(0.5)))], 
+    'g_addV_asXfirstX_repeatXaddEXnextX_toXaddVX_inVX_timesX5X_addEXnextX_toXselectXfirstXX': [(lambda g:g.addV().as_('first').repeat(__.addE('next').to(__.addV()).inV()).times(5).addE('next').to(__.select('first'))), (lambda g:g.V()), (lambda g:g.E()), (lambda g:g.E().hasLabel('next')), (lambda g:g.V()[0:1].bothE()), (lambda g:g.V()[0:1].inE()), (lambda g:g.V()[0:1].outE())], 
+    'g_V_hasXname_markoX_asXaX_outEXcreatedX_asXbX_inV_addEXselectXbX_labelX_toXaX': [(lambda g, v1=None:g.addV('person').property(T.id,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id,5).property('name','ripple').property('lang','java').as_('ripple').addV('person').property(T.id,6).property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property(T.id,7).property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property(T.id,8).property('weight',float(1.0)).addE('created').from_('marko').to('lop').property(T.id,9).property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property(T.id,10).property('weight',float(1.0)).addE('created').from_('josh').to('lop').property(T.id,11).property('weight',float(0.4)).addE('created').from_('peter').to('lop').property(T.id,12).property('weight',float(0.2))), (lambda g, v1=None:g.V().has('name','marko').as_('a').outE('created').as_('b').inV().addE(__.select('b').label()).to('a')), (lambda g, v1=None:g.E()), (lambda g, v1=None:g.V(v1).bothE()), (lambda g, v1=None:g.V(v1).inE('created')), (lambda g, v1=None:g.V(v1).in_('created').has('name','lop')), (lambda g, v1=None:g.V(v1).outE('created'))], 
+    'g_addEXV_outE_label_groupCount_orderXlocalX_byXvalues_descX_selectXkeysX_unfold_limitX1XX_fromXV_hasXname_vadasXX_toXV_hasXname_lopXX': [(lambda g, v2=None:g.addV('person').property(T.id,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id,5).property('name','ripple').property('lang','java').as_('ripple').addV('person').property(T.id,6).property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property(T.id,7).property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property(T.id,8).property('weight',float(1.0)).addE('created').from_('marko').to('lop').property(T.id,9).property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property(T.id,10).property('weight',float(1.0)).addE('created').from_('josh').to('lop').property(T.id,11).property('weight',float(0.4)).addE('created').from_('peter').to('lop').property(T.id,12).property('weight',float(0.2))), (lambda g, v2=None:g.addE(__.V().outE().label().groupCount().order(Scope.local).by(Column.values,Order.desc).select(Column.keys).unfold()[0:1]).from_(__.V().has('name','vadas')).to(__.V().has('name','lop'))), (lambda g, v2=None:g.E()), (lambda g, v2=None:g.V(v2).bothE()), (lambda g, v2=None:g.V(v2).inE('knows')), (lambda g, v2=None:g.V(v2).outE('created')), (lambda g, v2=None:g.V(v2).out('created').has('name','lop'))], 
+    'g_addEXknowsX_fromXaX_toXbX_propertyXweight_0_1X': [(lambda g, v6=None,xx1=None,v1=None:g.addV('person').property(T.id,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id,5).property('name','ripple').property('lang','java').as_('ripple').addV('person').property(T.id,6).property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property(T.id,7).property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property(T.id,8).property('weight',float(1.0)).addE('created').from_('marko').to('lop').property(T.id,9).property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property(T.id,10).property('weight',float(1.0)).addE('created').from_('josh').to('lop').property(T.id,11).property('weight',float(0.4)).addE('created').from_('peter').to('lop').property(T.id,12).property('weight',float(0.2))), (lambda g, v6=None,xx1=None,v1=None:g.addE('knows').from_(v1).to(v6).property('weight',xx1)), (lambda g, v6=None,xx1=None,v1=None:g.E()), (lambda g, v6=None,xx1=None,v1=None:g.V(v1).outE('knows')), (lambda g, v6=None,xx1=None,v1=None:g.V(v1).out('knows').has('name','peter'))], 
+    'g_VXaX_addEXknowsX_toXbX_propertyXweight_0_1X': [(lambda g, v6=None,xx1=None,v1=None:g.addV('person').property(T.id,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id,5).property('name','ripple').property('lang','java').as_('ripple').addV('person').property(T.id,6).property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property(T.id,7).property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property(T.id,8).property('weight',float(1.0)).addE('created').from_('marko').to('lop').property(T.id,9).property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property(T.id,10).property('weight',float(1.0)).addE('created').from_('josh').to('lop').property(T.id,11).property('weight',float(0.4)).addE('created').from_('peter').to('lop').property(T.id,12).property('weight',float(0.2))), (lambda g, v6=None,xx1=None,v1=None:g.V(v1).addE('knows').to(v6).property('weight',xx1)), (lambda g, v6=None,xx1=None,v1=None:g.E()), (lambda g, v6=None,xx1=None,v1=None:g.V(v1).outE('knows')), (lambda g, v6=None,xx1=None,v1=None:g.V(v1).out('knows').has('name','peter'))], 
+    'g_VX1X_addVXanimalX_propertyXage_selectXaX_byXageXX_propertyXname_puppyX': [(lambda g, vid1=None:g.addV('person').property(T.id,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id,5).property('name','ripple').property('lang','java').as_('ripple').addV('person').property(T.id,6).property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property(T.id,7).property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property(T.id,8).property('weight',float(1.0)).addE('created').from_('marko').to('lop').property(T.id,9).property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property(T.id,10).property('weight',float(1.0)).addE('created').from_('josh').to('lop').property(T.id,11).property('weight',float(0.4)).addE('created').from_('peter').to('lop').property(T.id,12).property('weight',float(0.2))), (lambda g, vid1=None:g.V(vid1).as_('a').addV('animal').property('age',__.select('a').by('age')).property('name','puppy')), (lambda g, vid1=None:g.V().has('animal','age',29))], 
+    'g_V_addVXanimalX_propertyXage_0X': [(lambda g:g.addV('person').property(T.id,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id,5).property('name','ripple').property('lang','java').as_('ripple').addV('person').property(T.id,6).property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property(T.id,7).property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property(T.id,8).property('weight',float(1.0)).addE('created').from_('marko').to('lop').property(T.id,9).property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property(T.id,10).property('weight',float(1.0)).addE('created').from_('josh').to('lop').property(T.id,11).property('weight',float(0.4)).addE('created').from_('peter').to('lop').property(T.id,12).property('weight',float(0.2))), (lambda g:g.V().addV('animal').property('age',0)), (lambda g:g.V().has('animal','age',0))], 
+    'g_addVXpersonX_propertyXname_stephenX': [(lambda g:g.addV('person').property(T.id,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id,5).property('name','ripple').property('lang','java').as_('ripple').addV('person').property(T.id,6).property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property(T.id,7).property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property(T.id,8).property('weight',float(1.0)).addE('created').from_('marko').to('lop').property(T.id,9).property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property(T.id,10).property('weight',float(1.0)).addE('created').from_('josh').to('lop').property(T.id,11).property('weight',float(0.4)).addE('created').from_('peter').to('lop').property(T.id,12).property('weight',float(0.2))), (lambda g:g.addV('person').property('name','stephen')), (lambda g:g.V().has('person','name','stephen'))], 
+    'g_V_hasLabelXpersonX_propertyXname_nullX': [(lambda g:g.addV('person').property(T.id,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id,5).property('name','ripple').property('lang','java').as_('ripple').addV('person').property(T.id,6).property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property(T.id,7).property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property(T.id,8).property('weight',float(1.0)).addE('created').from_('marko').to('lop').property(T.id,9).property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property(T.id,10).property('weight',float(1.0)).addE('created').from_('josh').to('lop').property(T.id,11).property('weight',float(0.4)).addE('created').from_('peter').to('lop').property(T.id,12).property('weight',float(0.2))), (lambda g:g.V().hasLabel('person').property('name',None)), (lambda g:g.V().properties('name'))], 
+    'g_addVXpersonX_propertyXsingle_name_stephenX_propertyXsingle_name_stephenmX': [(lambda g:g.addV('person').property(T.id,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id,5).property('name','ripple').property('lang','java').as_('ripple').addV('person').property(T.id,6).property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property(T.id,7).property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property(T.id,8).property('weight',float(1.0)).addE('created').from_('marko').to('lop').property(T.id,9).property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property(T.id,10).property('weight',float(1.0)).addE('created').from_('josh').to('lop').property(T.id,11).property('weight',float(0.4)).addE('created').from_('peter').to('lop').property(T.id,12).property('weight',float(0.2))), (lambda g:g.addV('person').property(Cardinality.single,'name','stephen').property(Cardinality.single,'name','stephenm')), (lambda g:g.V().has('person','name','stephen')), (lambda g:g.V().has('person','name','stephenm'))], 
+    'get_g_addVXpersonX_propertyXsingle_name_stephenX_propertyXsingle_name_stephenm_since_2010X': [(lambda g:g.addV('person').property(T.id,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id,5).property('name','ripple').property('lang','java').as_('ripple').addV('person').property(T.id,6).property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property(T.id,7).property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property(T.id,8).property('weight',float(1.0)).addE('created').from_('marko').to('lop').property(T.id,9).property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property(T.id,10).property('weight',float(1.0)).addE('created').from_('josh').to('lop').property(T.id,11).property('weight',float(0.4)).addE('created').from_('peter').to('lop').property(T.id,12).property('weight',float(0.2))), (lambda g:g.addV('person').property(Cardinality.single,'name','stephen').property(Cardinality.single,'name','stephenm','since',2010)), (lambda g:g.V().has('person','name','stephen')), (lambda g:g.V().has('person','name','stephenm')), (lambda g:g.V().has('person','name','stephenm').properties('name').has('since',2010))], 
+    'g_V_hasXname_markoX_propertyXfriendWeight_outEXknowsX_weight_sum__acl_privateX': [(lambda g:g.addV('person').property(T.id,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id,5).property('name','ripple').property('lang','java').as_('ripple').addV('person').property(T.id,6).property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property(T.id,7).property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property(T.id,8).property('weight',float(1.0)).addE('created').from_('marko').to('lop').property(T.id,9).property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property(T.id,10).property('weight',float(1.0)).addE('created').from_('josh').to('lop').property(T.id,11).property('weight',float(0.4)).addE('created').from_('peter').to('lop').property(T.id,12).property('weight',float(0.2))), (lambda g:g.V().has('name','marko').property('friendWeight',__.outE('knows').weight.sum(),'acl','private')), (lambda g:g.V().has('person','name','marko').has('friendWeight',float(1.5))), (lambda g:g.V().has('person','name','marko').properties('friendWeight').has('acl','private')), (lambda g:g.V().has('person','name','marko').properties('friendWeight').count())], 
+    'g_addVXanimalX_propertyXname_mateoX_propertyXname_gateoX_propertyXname_cateoX_propertyXage_5X': [(lambda g:g.addV('person').property(T.id,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id,5).property('name','ripple').property('lang','java').as_('ripple').addV('person').property(T.id,6).property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property(T.id,7).property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property(T.id,8).property('weight',float(1.0)).addE('created').from_('marko').to('lop').property(T.id,9).property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property(T.id,10).property('weight',float(1.0)).addE('created').from_('josh').to('lop').property(T.id,11).property('weight',float(0.4)).addE('created').from_('peter').to('lop').property(T.id,12).property('weight',float(0.2))), (lambda g:g.addV('animal').property('name','mateo').property('name','gateo').property('name','cateo').property('age',5)), (lambda g:g.V().hasLabel('animal').has('name','mateo').has('name','gateo').has('name','cateo').has('age',5))], 
+    'g_withSideEffectXa_markoX_addV_propertyXname_selectXaXX_name': [(lambda g:g.addV('person').property(T.id,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id,5).property('name','ripple').property('lang','java').as_('ripple').addV('person').property(T.id,6).property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property(T.id,7).property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property(T.id,8).property('weight',float(1.0)).addE('created').from_('marko').to('lop').property(T.id,9).property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property(T.id,10).property('weight',float(1.0)).addE('created').from_('josh').to('lop').property(T.id,11).property('weight',float(0.4)).addE('created').from_('peter').to('lop').property(T.id,12).property('weight',float(0.2))), (lambda g:g.withSideEffect('a','marko').addV().property('name',__.select('a')).name), (lambda g:g.V().has('name','marko'))], 
+    'g_addVXpersonX_propertyXsingle_name_stephenX_propertyXsingle_name_stephenm_since_2010X': [(lambda g:g.addV('person').property(T.id,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id,5).property('name','ripple').property('lang','java').as_('ripple').addV('person').property(T.id,6).property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property(T.id,7).property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property(T.id,8).property('weight',float(1.0)).addE('created').from_('marko').to('lop').property(T.id,9).property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property(T.id,10).property('weight',float(1.0)).addE('created').from_('josh').to('lop').property(T.id,11).property('weight',float(0.4)).addE('created').from_('peter').to('lop').property(T.id,12).property('weight',float(0.2))), (lambda g:g.addV('person').property(Cardinality.single,'name','stephen').property(Cardinality.single,'name','stephenm','since',2010)), (lambda g:g.V().has('name','stephen')), (lambda g:g.V().has('name','stephenm')), (lambda g:g.V().has('name','stephenm').properties('name').has('since',2010))], 
+    'g_V_addVXanimalX_propertyXname_valuesXnameXX_propertyXname_an_animalX_propertyXvaluesXnameX_labelX': [(lambda g:g.addV('person').property(T.id,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id,5).property('name','ripple').property('lang','java').as_('ripple').addV('person').property(T.id,6).property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property(T.id,7).property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property(T.id,8).property('weight',float(1.0)).addE('created').from_('marko').to('lop').property(T.id,9).property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property(T.id,10).property('weight',float(1.0)).addE('created').from_('josh').to('lop').property(T.id,11).property('weight',float(0.4)).addE('created').from_('peter').to('lop').property(T.id,12).property('weight',float(0.2))), (lambda g:g.V().addV('animal').property('name',__.name).property('name','an animal').property(__.name,__.label())), (lambda g:g.V().hasLabel('animal').has('name','marko').has('name','an animal').has('marko','person')), (lambda g:g.V().hasLabel('animal').has('name','vadas').has('name','an animal').has('vadas','person')), (lambda g:g.V().hasLabel('animal').has('name','lop').has('name','an animal').has('lop','software')), (lambda g:g.V().hasLabel('animal').has('name','josh').has('name','an animal').has('josh','person')), (lambda g:g.V().hasLabel('animal').has('name','ripple').has('name','an animal').has('ripple','software')), (lambda g:g.V().hasLabel('animal').has('name','peter').has('name','an animal').has('peter','person'))], 
+    'g_withSideEffectXa_testX_V_hasLabelXsoftwareX_propertyXtemp_selectXaXX_valueMapXname_tempX': [(lambda g:g.addV('person').property(T.id,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id,5).property('name','ripple').property('lang','java').as_('ripple').addV('person').property(T.id,6).property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property(T.id,7).property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property(T.id,8).property('weight',float(1.0)).addE('created').from_('marko').to('lop').property(T.id,9).property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property(T.id,10).property('weight',float(1.0)).addE('created').from_('josh').to('lop').property(T.id,11).property('weight',float(0.4)).addE('created').from_('peter').to('lop').property(T.id,12).property('weight',float(0.2))), (lambda g:g.withSideEffect('a','test').V().hasLabel('software').property('temp',__.select('a')).valueMap('name','temp'))], 
+    'g_withSideEffectXa_nameX_addV_propertyXselectXaX_markoX_name': [(lambda g:g.addV('person').property(T.id,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id,5).property('name','ripple').property('lang','java').as_('ripple').addV('person').property(T.id,6).property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property(T.id,7).property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property(T.id,8).property('weight',float(1.0)).addE('created').from_('marko').to('lop').property(T.id,9).property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property(T.id,10).property('weight',float(1.0)).addE('created').from_('josh').to('lop').property(T.id,11).property('weight',float(0.4)).addE('created').from_('peter').to('lop').property(T.id,12).property('weight',float(0.2))), (lambda g:g.withSideEffect('a','name').addV().property(__.select('a'),'marko').name), (lambda g:g.V().has('name','marko'))], 
+    'g_V_asXaX_hasXname_markoX_outXcreatedX_asXbX_addVXselectXaX_labelX_propertyXtest_selectXbX_labelX_valueMap_withXtokensX': [(lambda g:g.addV('person').property(T.id,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id,5).property('name','ripple').property('lang','java').as_('ripple').addV('person').property(T.id,6).property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property(T.id,7).property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property(T.id,8).property('weight',float(1.0)).addE('created').from_('marko').to('lop').property(T.id,9).property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property(T.id,10).property('weight',float(1.0)).addE('created').from_('josh').to('lop').property(T.id,11).property('weight',float(0.4)).addE('created').from_('peter').to('lop').property(T.id,12).property('weight',float(0.2))), (lambda g:g.V().as_('a').has('name','marko').out('created').as_('b').addV(__.select('a').label()).property('test',__.select('b').label()).valueMap().with_('~tinkerpop.valueMap.tokens')), (lambda g:g.V().has('person','test','software'))], 
+    'g_addVXV_hasXname_markoX_propertiesXnameX_keyX_label': [(lambda g:g.addV('person').property(T.id,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id,5).property('name','ripple').property('lang','java').as_('ripple').addV('person').property(T.id,6).property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property(T.id,7).property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property(T.id,8).property('weight',float(1.0)).addE('created').from_('marko').to('lop').property(T.id,9).property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property(T.id,10).property('weight',float(1.0)).addE('created').from_('josh').to('lop').property(T.id,11).property('weight',float(0.4)).addE('created').from_('peter').to('lop').property(T.id,12).property('weight',float(0.2))), (lambda g:g.addV(__.V().has('name','marko').properties('name').key()).label())], 
+    'g_addVXnullX_propertyXid_nullX': [(lambda g:g.addV(None).property(T.id,None)), (lambda g:g.V().hasLabel('vertex'))], 
+    'g_addV_propertyXlabel_personX': [(lambda g:g.addV().property(T.label,'person')), (lambda g:g.V().hasLabel('person'))], 
+    'g_V_coalesceXoutXfooX_outXbarXX': [(lambda g:g.V().coalesce(__.out('foo'),__.out('bar')))], 
+    'g_VX1X_coalesceXoutXknowsX_outXcreatedXX_valuesXnameX': [(lambda g, vid1=None:g.V(vid1).coalesce(__.out('knows'),__.out('created')).name)], 
+    'g_VX1X_coalesceXoutXcreatedX_outXknowsXX_valuesXnameX': [(lambda g, vid1=None:g.V(vid1).coalesce(__.out('created'),__.out('knows')).name)], 
+    'g_V_coalesceXoutXlikesX_outXknowsX_inXcreatedXX_groupCount_byXnameX': [(lambda g:g.V().coalesce(__.out('likes'),__.out('knows'),__.out('created')).groupCount().by('name'))], 
+    'g_V_coalesceXoutEXknowsX_outEXcreatedXX_otherV_path_byXnameX_byXlabelX': [(lambda g:g.V().coalesce(__.outE('knows'),__.outE('created')).otherV().path().by('name').by(T.label))], 
+    'g_V_outXcreatedX_order_byXnameX_coalesceXname_constantXxXX': [(lambda g:g.V().out('created').order().by('name').coalesce(__.name,__.constant('x')))], 
+    'g_V_connectedComponent_hasXcomponentX': [(lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().connectedComponent().has('gremlin.connectedComponentVertexProgram.component'))], 
+    'g_V_dedup_connectedComponent_hasXcomponentX': [(lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().dedup().connectedComponent().has('gremlin.connectedComponentVertexProgram.component'))], 
+    'g_V_hasLabelXsoftwareX_connectedComponent_project_byXnameX_byXcomponentX': [(lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().hasLabel('software').connectedComponent().project('name','component').by('name').by('gremlin.connectedComponentVertexProgram.component'))], 
+    'g_V_connectedComponent_withXEDGES_bothEXknowsXX_withXPROPERTY_NAME_clusterX_project_byXnameX_byXclusterX': [(lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().hasLabel('person').connectedComponent().with_('~tinkerpop.connectedComponent.edges',__.bothE('knows')).with_('~tinkerpop.connectedComponent.propertyName','cluster').project('name','cluster').by('name').by('cluster'))], 
+    'g_V_constantX123X': [(lambda g:g.V().constant(123))], 
+    'g_V_constantXnullX': [(lambda g:g.V().constant(None))], 
+    'g_V_chooseXhasLabelXpersonX_valuesXnameX_constantXinhumanXX': [(lambda g:g.V().choose(__.hasLabel('person'),__.name,__.constant('inhuman')))], 
+    'g_V_count': [(lambda g:g.V().count())], 
+    'g_V_out_count': [(lambda g:g.V().out().count())], 
+    'g_V_both_both_count': [(lambda g:g.V().both().both().count())], 
+    'g_V_fold_countXlocalX': [(lambda g:g.V().fold().count(Scope.local))], 
+    'g_V_hasXnoX_count': [(lambda g:g.V().has('no').count())], 
+    'g_V_whereXinXkknowsX_outXcreatedX_count_is_0XX_name': [(lambda g:g.V().where(__.in_('knows').out('created').count().is_(0)).name)], 
+    'g_V_repeatXoutX_timesX8X_count': [(lambda g:g.V().repeat(__.out()).times(8).count())], 
+    'g_V_repeatXoutX_timesX5X_asXaX_outXwrittenByX_asXbX_selectXa_bX_count': [(lambda g:g.V().repeat(__.out()).times(5).as_('a').out('writtenBy').as_('b').select('a','b').count())], 
+    'g_V_repeatXoutX_timesX3X_count': [(lambda g:g.V().repeat(__.out()).times(3).count())], 
+    'g_V_elementMap': [(lambda g:g.V().elementMap())], 
+    'g_V_elementMapXname_ageX': [(lambda g:g.V().elementMap('name','age'))], 
+    'g_EX11X_elementMap': [(lambda g, eid11=None:g.E(eid11).elementMap())], 
+    'g_V_asXaX_flatMapXselectXaXX': [(lambda g:g.V().as_('a').flatMap(__.select('a')))], 
+    'g_V_fold': [(lambda g:g.V().fold())], 
+    'g_V_fold_unfold': [(lambda g:g.V().fold().unfold())], 
+    'g_V_age_foldX0_plusX': [(lambda g:g.V().age.fold(0,Operator.sum))], 
+    'g_VX1X_V_valuesXnameX': [(lambda g, vid1=None:g.V(vid1).V().name)], 
+    'g_V_outXknowsX_V_name': [(lambda g:g.V().out('knows').V().name)], 
+    'g_V_hasXname_GarciaX_inXsungByX_asXsongX_V_hasXname_Willie_DixonX_inXwrittenByX_whereXeqXsongXX_name': [(lambda g:g.V().has('artist','name','Garcia').in_('sungBy').as_('song').V().has('artist','name','Willie_Dixon').in_('writtenBy').where(P.eq('song')).name)], 
+    'g_V_hasLabelXpersonX_asXpX_VXsoftwareX_addInEXuses_pX': [(lambda g, xx1=None,vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.addV('person').property(T.id,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id,5).property('name','ripple').property('lang','java').as_('ripple').addV('person').property(T.id,6).property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property(T.id,7).property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property(T.id,8).property('weight',float(1.0)).addE('created').from_('marko').to('lop').property(T.id,9).property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property(T.id,10).property('weight',float(1.0)).addE('created').from_('josh').to('lop').property(T.id,11).property('weight',float(0.4)).addE('created').from_('peter').to('lop').property(T.id,12).property('weight',float(0.2))), (lambda g, xx1=None,vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V().hasLabel('person').as_('p').V(xx1).addE('uses').from_('p')), (lambda g, xx1=None,vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.E().hasLabel('uses')), (lambda g, xx1=None,vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid1).outE('uses')), (lambda g, xx1=None,vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid2).outE('uses')), (lambda g, xx1=None,vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid3).inE('uses')), (lambda g, xx1=None,vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid4).outE('uses')), (lambda g, xx1=None,vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid5).inE('uses')), (lambda g, xx1=None,vid1=None,vid2=None,vid3=None,vid4=None,vid5=None,vid6=None:g.V(vid6).outE('uses'))], 
+    'g_V_hasLabelXsoftwareX_index_unfold': [(lambda g:g.V().hasLabel('software').index().unfold())], 
+    'g_V_hasLabelXsoftwareX_order_byXnameX_index_withXmapX': [(lambda g:g.V().hasLabel('software').order().by('name').index().with_('~tinkerpop.index.indexer',1))], 
+    'g_V_hasLabelXsoftwareX_name_fold_orderXlocalX_index_unfold_order_byXtailXlocal_1XX': [(lambda g:g.V().hasLabel('software').name.fold().order(Scope.local).index().unfold().order().by(__.tail(Scope.local,1)))], 
+    'g_V_hasLabelXpersonX_name_fold_orderXlocalX_index_withXmapX': [(lambda g:g.V().hasLabel('person').name.fold().order(Scope.local).index().with_('~tinkerpop.index.indexer',1))], 
+    'g_VX1X_repeatXboth_simplePathX_untilXhasXname_peterX_or_loops_isX3XX_hasXname_peterX_path_byXnameX': [(lambda g, vid1=None:g.V(vid1).repeat(__.both().simplePath()).until(__.has('name','peter').or_().loops().is_(3)).has('name','peter').path().by('name'))], 
+    'g_VX1X_repeatXboth_simplePathX_untilXhasXname_peterX_or_loops_isX2XX_hasXname_peterX_path_byXnameX': [(lambda g, vid1=None:g.V(vid1).repeat(__.both().simplePath()).until(__.has('name','peter').or_().loops().is_(2)).has('name','peter').path().by('name'))], 
+    'g_VX1X_repeatXboth_simplePathX_untilXhasXname_peterX_and_loops_isX3XX_hasXname_peterX_path_byXnameX': [(lambda g, vid1=None:g.V(vid1).repeat(__.both().simplePath()).until(__.has('name','peter').and_().loops().is_(3)).has('name','peter').path().by('name'))], 
+    'g_V_emitXhasXname_markoX_or_loops_isX2XX_repeatXoutX_valuesXnameX': [(lambda g:g.V().emit(__.has('name','marko').or_().loops().is_(2)).repeat(__.out()).name)], 
+    'g_VX1X_mapXnameX': [(lambda g, l1=None,vid1=None:g.V(vid1).map(l1))], 
+    'g_VX1X_outE_label_mapXlengthX': [(lambda g, l1=None,vid1=None:g.V(vid1).outE().label().map(l1))], 
+    'g_VX1X_out_mapXnameX_mapXlengthX': [(lambda g, l1=None,l2=None,vid1=None:g.V(vid1).out().map(l1).map(l2))], 
+    'g_VX1X_out_mapXlambdaXnameXX_mapXlambdaXlengthXX': [(lambda g, vid1=None:g.V(vid1).out().map(lambda: "it.get().value('name')").map(lambda: "it.get().toString().length()"))], 
+    'g_withPath_V_asXaX_out_mapXa_nameX': [(lambda g, l1=None:g.withPath().V().as_('a').out().map(l1))], 
+    'g_withPath_V_asXaX_out_out_mapXa_name_it_nameX': [(lambda g, l1=None:g.withPath().V().as_('a').out().out().map(l1))], 
+    'g_V_mapXselectXaXX': [(lambda g:g.V().as_('a').map(__.select('a')))], 
+    'g_V_mapXconstantXnullXX': [(lambda g:g.V().map(__.constant(None)))], 
+    'g_V_valueMap_matchXa_selectXnameX_bX': [(lambda g:g.V().valueMap().match(__.as_('a').select('name').as_('b')))], 
+    'g_V_matchXa_out_bX': [(lambda g:g.V().match(__.as_('a').out().as_('b')))], 
+    'g_V_matchXa_out_bX_selectXb_idX': [(lambda g:g.V().match(__.as_('a').out().as_('b')).select('b').by(T.id))], 
+    'g_V_matchXa_knows_b__b_created_cX': [(lambda g:g.V().match(__.as_('a').out('knows').as_('b'),__.as_('b').out('created').as_('c')))], 
+    'g_V_matchXb_created_c__a_knows_bX': [(lambda g:g.V().match(__.as_('b').out('created').as_('c'),__.as_('a').out('knows').as_('b')))], 
+    'g_V_matchXa_created_b__b_0created_cX_whereXa_neq_cX_selectXa_cX': [(lambda g:g.V().match(__.as_('a').out('created').as_('b'),__.as_('b').in_('created').as_('c')).where('a',P.neq('c')).select('a','c'))], 
+    'g_V_matchXd_0knows_a__d_hasXname_vadasX__a_knows_b__b_created_cX': [(lambda g:g.V().match(__.as_('d').in_('knows').as_('a'),__.as_('d').has('name','vadas'),__.as_('a').out('knows').as_('b'),__.as_('b').out('created').as_('c')))], 
+    'g_V_matchXa_created_lop_b__b_0created_29_c__c_whereXrepeatXoutX_timesX2XXX': [(lambda g:g.V().match(__.as_('a').out('created').has('name','lop').as_('b'),__.as_('b').in_('created').has('age',29).as_('c'),__.as_('c').where(__.repeat(__.out()).times(2))))], 
+    'g_V_asXaX_out_asXbX_matchXa_out_count_c__b_in_count_cX': [(lambda g:g.V().as_('a').out().as_('b').match(__.as_('a').out().count().as_('c'),__.as_('b').in_().count().as_('c')))], 
+    'g_V_matchXa__a_out_b__notXa_created_bXX': [(lambda g:g.V().match(__.as_('a').out().as_('b'),__.not_(__.as_('a').out('created').as_('b'))))], 
+    'g_V_matchXa_created_lop_b__b_0created_29_cX_whereXc_repeatXoutX_timesX2XX_selectXa_b_cX': [(lambda g:g.V().match(__.as_('a').out('created').has('name','lop').as_('b'),__.as_('b').in_('created').has('age',29).as_('c')).where(__.as_('c').repeat(__.out()).times(2)).select('a','b','c'))], 
+    'g_V_out_out_matchXa_0created_b__b_0knows_cX_selectXcX_outXcreatedX_name': [(lambda g:g.V().out().out().match(__.as_('a').in_('created').as_('b'),__.as_('b').in_('knows').as_('c')).select('c').out('created').name)], 
+    'g_V_matchXa_knows_b__b_created_c__a_created_cX_dedupXa_b_cX_selectXaX_byXnameX': [(lambda g:g.V().match(__.as_('a').out('knows').as_('b'),__.as_('b').out('created').as_('c'),__.as_('a').out('created').as_('c')).dedup('a','b','c').select('a').by('name'))], 
+    'g_V_matchXa_created_b__a_repeatXoutX_timesX2XX_selectXa_bX': [(lambda g:g.V().match(__.as_('a').out('created').as_('b'),__.as_('a').repeat(__.out()).times(2).as_('b')).select('a','b'))], 
+    'g_V_notXmatchXa_age_b__a_name_cX_whereXb_eqXcXX_selectXaXX_name': [(lambda g:g.V().not_(__.match(__.as_('a').age.as_('b'),__.as_('a').name.as_('c')).where('b',P.eq('c')).select('a')).name)], 
+    'g_V_matchXa_knows_b__andXa_created_c__b_created_c__andXb_created_count_d__a_knows_count_dXXX': [(lambda g:g.V().match(__.as_('a').out('knows').as_('b'),__.and_(__.as_('a').out('created').as_('c'),__.as_('b').out('created').as_('c'),__.and_(__.as_('b').out('created').count().as_('d'),__.as_('a').out('knows').count().as_('d')))))], 
+    'g_V_matchXa_whereXa_neqXcXX__a_created_b__orXa_knows_vadas__a_0knows_and_a_hasXlabel_personXX__b_0created_c__b_0created_count_isXgtX1XXX_selectXa_b_cX_byXidX': [(lambda g:g.V().match(__.where('a',P.neq('c')),__.as_('a').out('created').as_('b'),__.or_(__.as_('a').out('knows').has('name','vadas'),__.as_('a').in_('knows').and_().as_('a').has(T.label,'person')),__.as_('b').in_('created').as_('c'),__.as_('b').in_('created').count().is_(P.gt(1))).select('a','b','c').by(T.id))], 
+    'g_V_matchXa__a_both_b__b_both_cX_dedupXa_bX': [(lambda g:g.V().match(__.as_('a').both().as_('b'),__.as_('b').both().as_('c')).dedup('a','b'))], 
+    'g_V_matchXa_knows_b__b_created_lop__b_matchXb_created_d__d_0created_cX_selectXcX_cX_selectXa_b_cX': [(lambda g:g.V().match(__.as_('a').out('knows').as_('b'),__.as_('b').out('created').has('name','lop'),__.as_('b').match(__.as_('b').out('created').as_('d'),__.as_('d').in_('created').as_('c')).select('c').as_('c')).select('a','b','c'))], 
+    'g_V_matchXa_knows_b__a_created_cX': [(lambda g:g.V().match(__.as_('a').out('knows').as_('b'),__.as_('a').out('created').as_('c')))], 
+    'g_V_matchXwhereXandXa_created_b__b_0created_count_isXeqX3XXXX__a_both_b__whereXb_inXX': [(lambda g:g.V().match(__.where(__.and_(__.as_('a').out('created').as_('b'),__.as_('b').in_('created').count().is_(P.eq(3)))),__.as_('a').both().as_('b'),__.where(__.as_('b').in_())))], 
+    'g_V_matchXa_outEXcreatedX_order_byXweight_descX_limitX1X_inV_b__b_hasXlang_javaXX_selectXa_bX_byXnameX': [(lambda g:g.V().match(__.as_('a').outE('created').order().by('weight',Order.desc)[0:1].inV().as_('b'),__.as_('b').has('lang','java')).select('a','b').by('name'))], 
+    'g_V_matchXa_both_b__b_both_cX_dedupXa_bX_byXlabelX': [(lambda g:g.V().match(__.as_('a').both().as_('b'),__.as_('b').both().as_('c')).dedup('a','b').by(T.label))], 
+    'g_V_matchXa_created_b__b_0created_aX': [(lambda g:g.V().match(__.as_('a').out('created').as_('b'),__.as_('b').in_('created').as_('a')))], 
+    'g_V_asXaX_out_asXbX_matchXa_out_count_c__orXa_knows_b__b_in_count_c__and__c_isXgtX2XXXX': [(lambda g:g.V().as_('a').out().as_('b').match(__.as_('a').out().count().as_('c'),__.or_(__.as_('a').out('knows').as_('b'),__.as_('b').in_().count().as_('c').and_().as_('c').is_(P.gt(2)))))], 
+    'g_V_matchXa_knows_count_bX_selectXbX': [(lambda g:g.V().match(__.as_('a').out('knows').count().as_('b')).select('b'))], 
+    'g_V_matchXa_0sungBy_b__a_0writtenBy_c__b_writtenBy_d__c_sungBy_d__d_hasXname_GarciaXX': [(lambda g:g.V().match(__.as_('a').in_('sungBy').as_('b'),__.as_('a').in_('writtenBy').as_('c'),__.as_('b').out('writtenBy').as_('d'),__.as_('c').out('sungBy').as_('d'),__.as_('d').has('name','Garcia')))], 
+    'g_V_matchXa_hasXsong_name_sunshineX__a_mapX0followedBy_weight_meanX_b__a_0followedBy_c__c_filterXweight_whereXgteXbXXX_outV_dX_selectXdX_byXnameX': [(lambda g:g.V().match(__.as_('a').has('song','name','HERE COMES SUNSHINE'),__.as_('a').map(__.inE('followedBy').weight.mean()).as_('b'),__.as_('a').inE('followedBy').as_('c'),__.as_('c').filter(__.weight.where(P.gte('b'))).outV().as_('d')).select('d').by('name'))], 
+    'g_V_matchXa_0sungBy_b__a_0sungBy_c__b_writtenBy_d__c_writtenBy_e__d_hasXname_George_HarisonX__e_hasXname_Bob_MarleyXX': [(lambda g:g.V().match(__.as_('a').in_('sungBy').as_('b'),__.as_('a').in_('sungBy').as_('c'),__.as_('b').out('writtenBy').as_('d'),__.as_('c').out('writtenBy').as_('e'),__.as_('d').has('name','George_Harrison'),__.as_('e').has('name','Bob_Marley')))], 
+    'g_V_matchXa_hasXname_GarciaX__a_0writtenBy_b__a_0sungBy_bX': [(lambda g:g.V().match(__.as_('a').has('name','Garcia'),__.as_('a').in_('writtenBy').as_('b'),__.as_('a').in_('sungBy').as_('b')))], 
+    'g_V_hasLabelXsongsX_matchXa_name_b__a_performances_cX_selectXb_cX_count': [(lambda g:g.V().hasLabel('song').match(__.as_('a').name.as_('b'),__.as_('a').performances.as_('c')).select('b','c').count())], 
+    'g_V_matchXa_followedBy_count_isXgtX10XX_b__a_0followedBy_count_isXgtX10XX_bX_count': [(lambda g:g.V().match(__.as_('a').out('followedBy').count().is_(P.gt(10)).as_('b'),__.as_('a').in_('followedBy').count().is_(P.gt(10)).as_('b')).count())], 
+    'g_V_matchXa_0sungBy_b__a_0writtenBy_c__b_writtenBy_dX_whereXc_sungBy_dX_whereXd_hasXname_GarciaXX': [(lambda g:g.V().match(__.as_('a').in_('sungBy').as_('b'),__.as_('a').in_('writtenBy').as_('c'),__.as_('b').out('writtenBy').as_('d')).where(__.as_('c').out('sungBy').as_('d')).where(__.as_('d').has('name','Garcia')))], 
+    'g_V_matchXa_hasXname_GarciaX__a_0writtenBy_b__b_followedBy_c__c_writtenBy_d__whereXd_neqXaXXX': [(lambda g:g.V().match(__.as_('a').has('name','Garcia'),__.as_('a').in_('writtenBy').as_('b'),__.as_('b').out('followedBy').as_('c'),__.as_('c').out('writtenBy').as_('d'),__.where('d',P.neq('a'))))], 
+    'g_V_matchXa_outXknowsX_name_bX_identity': [(lambda g:g.V().match(__.as_('a').out('knows').name.as_('b')).identity())], 
+    'g_V_outE_mathX0_minus_itX_byXweightX': [(lambda g:g.V().outE().math('0-_').by('weight'))], 
+    'g_V_hasXageX_valueMap_mathXit_plus_itXbyXselectXageX_unfoldXX': [(lambda g:g.V().has('age').valueMap().math('_+_').by(__.select('age').unfold()))], 
+    'g_V_asXaX_outXknowsX_asXbX_mathXa_plus_bX_byXageX': [(lambda g:g.V().as_('a').out('knows').as_('b').math('a + b').by('age'))], 
+    'g_withSideEffectXx_100X_V_age_mathX__plus_xX': [(lambda g, xx1=None:g.withSideEffect('x',xx1).V().age.math('_ + x'))], 
+    'g_V_asXaX_outXcreatedX_asXbX_mathXb_plus_aX_byXinXcreatedX_countX_byXageX': [(lambda g:g.V().as_('a').out('created').as_('b').math('b + a').by(__.in_('created').count()).by('age'))], 
+    'g_withSackX1X_injectX1X_repeatXsackXsumX_byXconstantX1XXX_timesX5X_emit_mathXsin__X_byXsackX': [(lambda g:g.withSack(1).inject(1).repeat(__.sack(Operator.sum).by(__.constant(1))).times(5).emit().math('sin _').by(__.sack()))], 
+    'g_V_projectXa_b_cX_byXbothE_weight_sumX_byXbothE_countX_byXnameX_order_byXmathXa_div_bX_descX_selectXcX': [(lambda g:g.V().project('a','b','c').by(__.bothE().weight.sum()).by(__.bothE().count()).by('name').order().by(__.math('a / b'),Order.desc).select('c'))], 
+    'g_V_age_max': [(lambda g:g.V().age.max())], 
+    'g_V_foo_max': [(lambda g:g.V().foo.max())], 
+    'g_V_name_max': [(lambda g:g.V().name.max())], 
+    'g_V_age_fold_maxXlocalX': [(lambda g:g.V().age.fold().max(Scope.local))], 
+    'g_V_foo_fold_maxXlocalX': [(lambda g:g.V().foo.fold().max(Scope.local))], 
+    'g_V_name_fold_maxXlocalX': [(lambda g:g.V().name.fold().max(Scope.local))], 
+    'g_V_repeatXbothX_timesX5X_age_max': [(lambda g:g.V().repeat(__.both()).times(5).age.max())], 
+    'g_V_hasLabelXsoftwareX_group_byXnameX_byXbothE_weight_maxX': [(lambda g:g.V().hasLabel('software').group().by('name').by(__.bothE().weight.max()))], 
+    'g_V_age_mean': [(lambda g:g.V().age.mean())], 
+    'g_V_foo_mean': [(lambda g:g.V().foo.mean())], 
+    'g_V_age_fold_meanXlocalX': [(lambda g:g.V().age.fold().mean(Scope.local))], 
+    'g_V_foo_fold_meanXlocalX': [(lambda g:g.V().foo.fold().mean(Scope.local))], 
+    'g_V_hasLabelXsoftwareX_group_byXnameX_byXbothE_weight_meanX': [(lambda g:g.V().hasLabel('software').group().by('name').by(__.bothE().weight.mean()))], 
+    'g_V_age_min': [(lambda g:g.V().age.min())], 
+    'g_V_foo_min': [(lambda g:g.V().foo.min())], 
+    'g_V_name_min': [(lambda g:g.V().name.min())], 
+    'g_V_age_fold_minXlocalX': [(lambda g:g.V().age.fold().min(Scope.local))], 
+    'g_V_foo_fold_minXlocalX': [(lambda g:g.V().foo.fold().min(Scope.local))], 
+    'g_V_name_fold_minXlocalX': [(lambda g:g.V().name.fold().min(Scope.local))], 
+    'g_V_repeatXbothX_timesX5X_age_min': [(lambda g:g.V().repeat(__.both()).times(5).age.min())], 
+    'g_V_hasLabelXsoftwareX_group_byXnameX_byXbothE_weight_minX': [(lambda g:g.V().hasLabel('software').group().by('name').by(__.bothE().weight.min()))], 
+    'g_V_foo_injectX9999999999X_min': [(lambda g, xx1=None:g.V().foo.inject(xx1).min())], 
+    'g_V_name_order': [(lambda g:g.V().name.order())], 
+    'g_V_name_order_byXa1_b1X_byXb2_a2X': [(lambda g, c1=None,c2=None:g.V().name.order().by(c1).by(c2))], 
+    'g_V_order_byXname_ascX_name': [(lambda g:g.V().order().by('name',Order.asc).name)], 
+    'g_V_order_byXnameX_name': [(lambda g:g.V().order().by('name').name)], 
+    'g_V_outE_order_byXweight_descX_weight': [(lambda g:g.V().outE().order().by('weight',Order.desc).weight)], 
+    'g_V_order_byXname_a1_b1X_byXname_b2_a2X_name': [(lambda g, c1=None,c2=None:g.V().order().by('name',c1).by('name',c2).name)], 
+    'g_V_asXaX_outXcreatedX_asXbX_order_byXshuffleX_selectXa_bX': [(lambda g:g.V().as_('a').out('created').as_('b').order().by(Order.shuffle).select('a','b'))], 
+    'g_V_both_hasLabelXpersonX_order_byXage_descX_limitX5X_name': [(lambda g:g.V().both().hasLabel('person').order().by('age',Order.desc)[0:5].name)], 
+    'g_V_properties_order_byXkey_descX_key': [(lambda g:g.V().properties().order().by(T.key,Order.desc).key())], 
+    'g_V_hasLabelXpersonX_order_byXvalueXageX_descX_name': [(lambda g, l1=None:g.V().hasLabel('person').order().by(l1,Order.desc).name)], 
+    'g_V_hasLabelXpersonX_group_byXnameX_byXoutE_weight_sumX_orderXlocalX_byXvaluesX': [(lambda g:g.V().hasLabel('person').group().by('name').by(__.outE().weight.sum()).order(Scope.local).by(Column.values))], 
+    'g_V_mapXbothE_weight_foldX_order_byXsumXlocalX_descX': [(lambda g:g.V().map(__.bothE().weight.fold()).order().by(__.sum(Scope.local),Order.desc))], 
+    'g_V_group_byXlabelX_byXname_order_byXdescX_foldX': [(lambda g:g.V().group().by(T.label).by(__.name.order().by(Order.desc).fold()))], 
+    'g_V_hasLabelXpersonX_group_byXnameX_byXoutE_weight_sumX_unfold_order_byXvalues_descX': [(lambda g:g.V().hasLabel('person').group().by('name').by(__.outE().weight.sum()).unfold().order().by(Column.values,Order.desc))], 
+    'g_V_asXvX_mapXbothE_weight_foldX_sumXlocalX_asXsX_selectXv_sX_order_byXselectXsX_descX': [(lambda g:g.V().as_('v').map(__.bothE().weight.fold()).sum(Scope.local).as_('s').select('v','s').order().by(__.select('s'),Order.desc))], 
+    'g_V_hasLabelXpersonX_fold_orderXlocalX_byXageX': [(lambda g:g.V().hasLabel('person').fold().order(Scope.local).by('age'))], 
+    'g_V_both_hasLabelXpersonX_order_byXage_descX_name': [(lambda g:g.V().both().hasLabel('person').order().by('age',Order.desc).name)], 
+    'g_V_order_byXoutE_count_descX': [(lambda g:g.V().order().by(__.outE().count(),Order.desc))], 
+    'g_V_hasLabelXpersonX_order_byXageX': [(lambda g:g.V().hasLabel('person').order().by('age'))], 
+    'g_VX1X_hasXlabel_personX_mapXmapXint_ageXX_orderXlocalX_byXvalues_descX_byXkeys_ascX': [(lambda g, l1=None,v1=None:g.V(v1).hasLabel('person').map(l1).order(Scope.local).by(Column.values,Order.desc).by(Column.keys,Order.asc))], 
+    'g_VX1X_elementMap_orderXlocalX_byXkeys_descXunfold': [(lambda g, vid1=None:g.V(vid1).elementMap().order(Scope.local).by(Column.keys,Order.desc).unfold())], 
+    'g_V_pageRank_hasXpageRankX': [(lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().pageRank().has('gremlin.pageRankVertexProgram.pageRank')), (lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().pageRank().has('gremlin.pageRankVertexProgram.pageRank'))], 
+    'g_V_outXcreatedX_pageRank_withXedges_bothEX_withXpropertyName_projectRankX_withXtimes_0X_valueMapXname_projectRankX': [(lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().out('created').pageRank().with_('~tinkerpop.pageRank.edges',__.bothE()).with_('~tinkerpop.pageRank.propertyName','projectRank').with_('~tinkerpop.pageRank.times',0).valueMap('name','projectRank'))], 
+    'g_V_pageRank_order_byXpageRank_descX_byXnameX_name': [(lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().pageRank().order().by('gremlin.pageRankVertexProgram.pageRank',Order.desc).by('name').name)], 
+    'g_V_pageRank_order_byXpageRank_descX_name_limitX2X': [(lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().pageRank().order().by('gremlin.pageRankVertexProgram.pageRank',Order.desc).name[0:2])], 
+    'g_V_pageRank_withXedges_outEXknowsXX_withXpropertyName_friendRankX_project_byXnameX_byXvaluesXfriendRankX_mathX': [(lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().pageRank().with_('~tinkerpop.pageRank.edges',__.outE('knows')).with_('~tinkerpop.pageRank.propertyName','friendRank').project('name','friendRank').by('name').by(__.friendRank.math('ceil(_ * 100)')))], 
+    'g_V_hasLabelXpersonX_pageRank_withXpropertyName_kpageRankX_project_byXnameX_byXvaluesXpageRankX_mathX': [(lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().hasLabel('person').pageRank().with_('~tinkerpop.pageRank.propertyName','pageRank').project('name','pageRank').by('name').by(__.values('pageRank').math('ceil(_ * 100)')))], 
+    'g_V_pageRank_withXpropertyName_pageRankX_asXaX_outXknowsX_pageRank_asXbX_selectXa_bX_by_byXmathX': [(lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().pageRank().with_('~tinkerpop.pageRank.propertyName','pageRank').as_('a').out('knows').values('pageRank').as_('b').select('a','b').by().by(__.math('ceil(_ * 100)')))], 
+    'g_V_hasLabelXsoftwareX_hasXname_rippleX_pageRankX1X_withXedges_inEXcreatedX_withXtimes_1X_withXpropertyName_priorsX_inXcreatedX_unionXboth__identityX_valueMapXname_priorsX': [(lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().hasLabel('software').has('name','ripple').pageRank(float(1.0)).with_('~tinkerpop.pageRank.edges',__.inE('created')).with_('~tinkerpop.pageRank.times',1).with_('~tinkerpop.pageRank.propertyName','priors').in_('created').union(__.both(),__.identity()).valueMap('name','priors'))], 
+    'g_V_outXcreatedX_groupXmX_byXlabelX_pageRankX1X_withXpropertyName_pageRankX_withXedges_inEX_withXtimes_1X_inXcreatedX_groupXmX_byXpageRankX_capXmX': [(lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().out('created').group('m').by(T.label).pageRank(float(1.0)).with_('~tinkerpop.pageRank.propertyName','pageRank').with_('~tinkerpop.pageRank.edges',__.inE()).with_('~tinkerpop.pageRank.times',1).in_('created').group('m').by('pageRank').cap('m'))], 
+    'g_VX1X_name_path': [(lambda g, vid1=None:g.V(vid1).name.path())], 
+    'g_VX1X_out_path_byXageX_byXnameX': [(lambda g, vid1=None:g.V(vid1).out().path().by('age').by('name'))], 
+    'g_V_repeatXoutX_timesX2X_path_byXitX_byXnameX_byXlangX': [(lambda g:g.V().repeat(__.out()).times(2).path().by().by('name').by('lang'))], 
+    'g_V_out_out_path_byXnameX_byXageX': [(lambda g:g.V().out().out().path().by('name').by('age'))], 
+    'g_V_asXaX_hasXname_markoX_asXbX_hasXage_29X_asXcX_path': [(lambda g:g.V().as_('a').has('name','marko').as_('b').has('age',29).as_('c').path())], 
+    'g_VX1X_outEXcreatedX_inV_inE_outV_path': [(lambda g, vid1=None:g.V(vid1).outE('created').inV().inE().outV().path())], 
+    'g_V_asXaX_out_asXbX_out_asXcX_path_fromXbX_toXcX_byXnameX': [(lambda g:g.V().as_('a').out().as_('b').out().as_('c').path().from_('b').to('c').by('name'))], 
+    'g_V_peerPressure_hasXclusterX': [(lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().peerPressure().has('gremlin.peerPressureVertexProgram.cluster')), (lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().peerPressure().has('gremlin.peerPressureVertexProgram.cluster'))], 
+    'g_V_peerPressure_withXpropertyName_clusterX_withXedges_outEXknowsXX_pageRankX1X_byXrankX_withXedges_outEXknowsX_withXtimes_2X_group_byXclusterX_byXrank_sumX_limitX100X': [(lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().peerPressure().with_('~tinkerpop.peerPressure.propertyName','cluster').with_('~tinkerpop.peerPressure.edges',__.outE('knows')).pageRank(float(1.0)).with_('~tinkerpop.pageRank.propertyName','rank').with_('~tinkerpop.pageRank.edges',__.outE('knows')).with_('~tinkerpop.pageRank.times',1).group().by('cluster').by(__.rank.sum())[0:100])], 
+    'g_V_hasXname_rippleX_inXcreatedX_peerPressure_withXedges_outEX_withyXpropertyName_clusterX_repeatXunionXidentity__bothX_timesX2X_dedup_valueMapXname_clusterX': [(lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().has('name','ripple').in_('created').peerPressure().with_('~tinkerpop.peerPressure.edges',__.outE()).with_('~tinkerpop.peerPressure.propertyName','cluster').repeat(__.union(__.identity(),__.both())).times(2).dedup().valueMap('name','cluster'))], 
+    'g_V_hasLabelXpersonX_projectXa_bX_byXoutE_countX_byXageX': [(lambda g:g.V().hasLabel('person').project('a','b').by(__.outE().count()).by('age'))], 
+    'g_V_outXcreatedX_projectXa_bX_byXnameX_byXinXcreatedX_countX_order_byXselectXbX__descX_selectXaX': [(lambda g:g.V().out('created').project('a','b').by('name').by(__.in_('created').count()).order().by(__.select('b'),Order.desc).select('a'))], 
+    'g_V_valueMap_projectXxX_byXselectXnameXX': [(lambda g:g.V().valueMap().project('x').by(__.select('name')))], 
+    'g_V_hasXageX_propertiesXnameX': [(lambda g:g.V().has('age').properties('name').value())], 
+    'g_V_hasXageX_propertiesXname_ageX_value': [(lambda g:g.V().has('age').properties('name','age').value())], 
+    'g_V_hasXageX_propertiesXage_nameX_value': [(lambda g:g.V().has('age').properties('age','name').value())], 
+    'get_g_VX1X_asXaX_outXknowsX_asXbX_selectXa_bX': [(lambda g, vid1=None:g.V(vid1).as_('a').out('knows').as_('b').select('a','b'))], 
+    'g_VX1X_asXaX_outXknowsX_asXbX_selectXa_bX_byXnameX': [(lambda g, vid1=None:g.V(vid1).as_('a').out('knows').as_('b').select('a','b').by('name'))], 
+    'g_VX1X_asXaX_outXknowsX_asXbX_selectXaX': [(lambda g, vid1=None:g.V(vid1).as_('a').out('knows').as_('b').select('a'))], 
+    'g_VX1X_asXaX_outXknowsX_asXbX_selectXaX_byXnameX': [(lambda g, vid1=None:g.V(vid1).as_('a').out('knows').as_('b').select('a').by('name'))], 
+    'g_V_asXaX_out_asXbX_selectXa_bX_byXnameX': [(lambda g:g.V().as_('a').out().as_('b').select('a','b').by('name'))], 
+    'g_V_asXaX_out_aggregateXxX_asXbX_selectXa_bX_byXnameX': [(lambda g:g.V().as_('a').out().aggregate('x').as_('b').select('a','b').by('name'))], 
+    'g_V_asXaX_name_order_asXbX_selectXa_bX_byXnameX_by_XitX': [(lambda g:g.V().as_('a').name.order().as_('b').select('a','b').by('name').by())], 
+    'g_V_hasXname_gremlinX_inEXusesX_order_byXskill_ascX_asXaX_outV_asXbX_selectXa_bX_byXskillX_byXnameX': [(lambda g:g.V().has('name','gremlin').inE('uses').order().by('skill',Order.asc).as_('a').outV().as_('b').select('a','b').by('skill').by('name'))], 
+    'g_V_hasXname_isXmarkoXX_asXaX_selectXaX': [(lambda g:g.V().has('name',__.is_('marko')).as_('a').select('a'))], 
+    'g_V_label_groupCount_asXxX_selectXxX': [(lambda g:g.V().label().groupCount().as_('x').select('x'))], 
+    'g_V_hasLabelXpersonX_asXpX_mapXbothE_label_groupCountX_asXrX_selectXp_rX': [(lambda g:g.V().hasLabel('person').as_('p').map(__.bothE().label().groupCount()).as_('r').select('p','r'))], 
+    'g_V_chooseXoutE_count_isX0X__asXaX__asXbXX_chooseXselectXaX__selectXaX__selectXbXX': [(lambda g, xx1=None:g.V().choose(__.outE().count().is_(xx1),__.as_('a'),__.as_('b')).choose(__.select('a'),__.select('a'),__.select('b')))], 
+    'g_VX1X_groupXaX_byXconstantXaXX_byXnameX_selectXaX_selectXaX': [(lambda g, vid1=None:g.V(vid1).group('a').by(__.constant('a')).by(__.name).barrier().select('a').select('a'))], 
+    'g_VX1X_asXhereX_out_selectXhereX': [(lambda g, vid1=None:g.V(vid1).as_('here').out().select('here'))], 
+    'g_VX4X_out_asXhereX_hasXlang_javaX_selectXhereX': [(lambda g, vid4=None:g.V(vid4).as_('here').out().select('here'))], 
+    'g_VX4X_out_asXhereX_hasXlang_javaX_selectXhereX_name': [(lambda g, vid4=None:g.V(vid4).out().as_('here').has('lang','java').select('here').name)], 
+    'g_VX1X_outE_asXhereX_inV_hasXname_vadasX_selectXhereX': [(lambda g, vid1=None:g.V(vid1).outE().as_('here').inV().has('name','vadas').select('here'))], 
+    'g_VX1X_outEXknowsX_hasXweight_1X_asXhereX_inV_hasXname_joshX_selectXhereX': [(lambda g, vid1=None:g.V(vid1).outE('knows').has('weight',float(1.0)).as_('here').inV().has('name','josh').select('here'))], 
+    'g_VX1X_outEXknowsX_asXhereX_hasXweight_1X_asXfakeX_inV_hasXname_joshX_selectXhereX': [(lambda g, vid1=None:g.V(vid1).outE('knows').as_('here').has('weight',float(1.0)).as_('fake').inV().has('name','josh').select('here'))], 
+    'g_V_asXhereXout_name_selectXhereX': [(lambda g:g.V().as_('here').out().name.select('here'))], 
+    'g_V_outXcreatedX_unionXasXprojectX_inXcreatedX_hasXname_markoX_selectXprojectX__asXprojectX_inXcreatedX_inXknowsX_hasXname_markoX_selectXprojectXX_groupCount_byXnameX': [(lambda g:g.V().out('created').union(__.as_('project').in_('created').has('name','marko').select('project'),__.as_('project').in_('created').in_('knows').has('name','marko').select('project')).groupCount().by('name'))], 
+    'g_V_untilXout_outX_repeatXin_asXaXX_selectXaX_byXtailXlocalX_nameX': [(lambda g:g.V().until(__.out().out()).repeat(__.in_().as_('a')).select('a').by(__.tail(Scope.local).name))], 
+    'g_V_outE_weight_groupCount_selectXkeysX_unfold': [(lambda g:g.V().outE().weight.groupCount().select(Column.keys).unfold())], 
+    'g_V_hasLabelXsoftwareX_asXnameX_asXlanguageX_asXcreatorsX_selectXname_language_creatorsX_byXnameX_byXlangX_byXinXcreatedX_name_fold_orderXlocalXX': [(lambda g:g.V().hasLabel('software').as_('name').as_('language').as_('creators').select('name','language','creators').by('name').by('lang').by(__.in_('created').name.fold().order(Scope.local)))], 
+    'g_V_outE_weight_groupCount_unfold_selectXkeysX_unfold': [(lambda g:g.V().outE().weight.groupCount().unfold().select(Column.keys).unfold())], 
+    'g_V_outE_weight_groupCount_unfold_selectXvaluesX_unfold': [(lambda g:g.V().outE().weight.groupCount().unfold().select(Column.values).unfold())], 
+    'g_V_untilXout_outX_repeatXin_asXaX_in_asXbXX_selectXa_bX_byXnameX': [(lambda g:g.V().until(__.out().out()).repeat(__.in_().as_('a').in_().as_('b')).select('a','b').by('name'))], 
+    'g_V_outE_weight_groupCount_selectXvaluesX_unfold': [(lambda g:g.V().outE().weight.groupCount().select(Column.values).unfold())], 
+    'g_VX1X_asXaX_outXknowsX_asXbX_selectXa_bX': [(lambda g, vid1=None:g.V(vid1).as_('a').out('knows').as_('b').select('a','b'))], 
+    'g_V_asXaX_whereXoutXknowsXX_selectXaX': [(lambda g:g.V().as_('a').where(__.out('knows')).select('a'))], 
+    'g_VX1X_asXaX_repeatXout_asXaXX_timesX2X_selectXfirst_aX': [(lambda g, vid1=None:g.V(vid1).as_('a').repeat(__.out().as_('a')).times(2).select(Pop.first,'a'))], 
+    'g_V_asXaX_outXknowsX_asXbX_localXselectXa_bX_byXnameXX': [(lambda g:g.V().as_('a').out('knows').as_('b').local(__.select('a','b').by('name')))], 
+    'g_VX1X_asXaX_repeatXout_asXaXX_timesX2X_selectXlast_aX': [(lambda g, vid1=None:g.V(vid1).as_('a').repeat(__.out().as_('a')).times(2).select(Pop.last,'a'))], 
+    'g_VX1X_outEXknowsX_asXhereX_hasXweight_1X_inV_hasXname_joshX_selectXhereX': [(lambda g, vid1=None:g.V(vid1).outE('knows').as_('here').has('weight',float(1.0)).inV().has('name','josh').select('here'))], 
+    'g_V_asXaX_hasXname_markoX_asXbX_asXcX_selectXa_b_cX_by_byXnameX_byXageX': [(lambda g:g.V().as_('a').has('name','marko').as_('b').as_('c').select('a','b','c').by().by('name').by('age'))], 
+    'g_V_outE_weight_groupCount_selectXvaluesX_unfold_groupCount_selectXvaluesX_unfold': [(lambda g:g.V().outE().weight.groupCount().select(Column.values).unfold().groupCount().select(Column.values).unfold())], 
+    'g_V_asXaX_groupXmX_by_byXbothE_countX_barrier_selectXmX_selectXselectXaXX': [(lambda g:g.V().as_('a').group('m').by().by(__.bothE().count()).barrier().select('m').select(__.select('a')))], 
+    'g_V_asXaX_groupXmX_by_byXbothE_countX_barrier_selectXmX_selectXselectXaXX_byXmathX_plus_XX': [(lambda g:g.V().as_('a').group('m').by().by(__.bothE().count()).barrier().select('m').select(__.select('a')).by(__.math('_+_')))], 
+    'g_V_asXaX_outXknowsX_asXaX_selectXall_constantXaXX': [(lambda g:g.V().as_('a').out('knows').as_('a').select(Pop.all_,__.constant('a')))], 
+    'g_V_selectXaX': [(lambda g:g.V().select('a'))], 
+    'g_V_selectXaX_count': [(lambda g:g.V().select('a').count())], 
+    'g_V_selectXa_bX': [(lambda g:g.V().select('a','b'))], 
+    'g_V_valueMap_selectXaX': [(lambda g:g.V().valueMap().select('a'))], 
+    'g_V_valueMap_selectXa_bX': [(lambda g:g.V().valueMap().select('a','b'))], 
+    'g_V_selectXfirst_aX': [(lambda g:g.V().select(Pop.first,'a'))], 
+    'g_V_selectXfirst_a_bX': [(lambda g:g.V().select(Pop.first,'a','b'))], 
+    'g_V_valueMap_selectXfirst_aX': [(lambda g:g.V().valueMap().select(Pop.first,'a'))], 
+    'g_V_valueMap_selectXfirst_a_bX': [(lambda g:g.V().valueMap().select(Pop.first,'a','b'))], 
+    'g_V_selectXlast_aX': [(lambda g:g.V().select(Pop.last,'a'))], 
+    'g_V_selectXlast_a_bX': [(lambda g:g.V().select(Pop.last,'a','b'))], 
+    'g_V_valueMap_selectXlast_aX': [(lambda g:g.V().valueMap().select(Pop.last,'a'))], 
+    'g_V_valueMap_selectXlast_a_bX': [(lambda g:g.V().valueMap().select(Pop.last,'a','b'))], 
+    'g_V_selectXall_aX': [(lambda g:g.V().select(Pop.all_,'a'))], 
+    'g_V_selectXall_a_bX': [(lambda g:g.V().select(Pop.all_,'a','b'))], 
+    'g_V_valueMap_selectXall_aX': [(lambda g:g.V().valueMap().select(Pop.all_,'a'))], 
+    'g_V_valueMap_selectXall_a_bX': [(lambda g:g.V().valueMap().select(Pop.all_,'a','b'))], 
+    'g_V_asXa_bX_out_asXcX_path_selectXkeysX': [(lambda g:g.V().as_('a','b').out().as_('c').path().select(Column.keys)), (lambda g:g.V().as_('a','b').out().as_('c').path().select(Column.keys))], 
+    'g_V_hasXperson_name_markoX_barrier_asXaX_outXknows_selectXaX': [(lambda g:g.V().has('person','name','marko').barrier().as_('a').out('knows').select('a'))], 
+    'g_V_hasXperson_name_markoX_elementMapXnameX_asXaX_unionXidentity_identityX_selectXaX_selectXnameX': [(lambda g:g.V().has('person','name','marko').elementMap('name').as_('a').union(__.identity(),__.identity()).select('a').select('name'))], 
+    'g_V_hasXperson_name_markoX_count_asXaX_unionXidentity_identityX_selectXaX': [(lambda g:g.V().has('person','name','marko').count().as_('a').union(__.identity(),__.identity()).select('a'))], 
+    'g_V_hasXperson_name_markoX_path_asXaX_unionXidentity_identityX_selectXaX_unfold': [(lambda g:g.V().has('person','name','marko').path().as_('a').union(__.identity(),__.identity()).select('a').unfold())], 
+    'g_EX11X_propertiesXweightX_asXaX_selectXaX_byXkeyX': [(lambda g, eid11=None:g.E(eid11).properties('weight').as_('a').select('a').by(T.key))], 
+    'g_EX11X_propertiesXweightX_asXaX_selectXaX_byXvalueX': [(lambda g, eid11=None:g.E(eid11).properties('weight').as_('a').select('a').by(T.value))], 
+    'g_V_shortestPath': [(lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().identity().shortestPath())], 
+    'g_V_both_dedup_shortestPath': [(lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().both().dedup().shortestPath())], 
+    'g_V_shortestPath_edgesIncluded': [(lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().identity().shortestPath().with_('~tinkerpop.shortestPath.includeEdges'))], 
+    'g_V_shortestPath_directionXINX': [(lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().identity().shortestPath().with_('~tinkerpop.shortestPath.edges',Direction.IN))], 
+    'g_V_shortestPath_edgesXoutEX': [(lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().identity().shortestPath().with_('~tinkerpop.shortestPath.edges',__.outE()))], 
+    'g_V_shortestPath_edgesIncluded_edgesXoutEX': [(lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().identity().shortestPath().with_('~tinkerpop.shortestPath.includeEdges').with_('~tinkerpop.shortestPath.edges',__.outE()))], 
+    'g_V_hasXname_markoX_shortestPath': [(lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().has('name','marko').shortestPath())], 
+    'g_V_shortestPath_targetXhasXname_markoXX': [(lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().identity().shortestPath().with_('~tinkerpop.shortestPath.target',__.has('name','marko')))], 
+    'g_V_shortestPath_targetXvaluesXnameX_isXmarkoXX': [(lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().identity().shortestPath().with_('~tinkerpop.shortestPath.target',__.name.is_('marko')))], 
+    'g_V_hasXname_markoX_shortestPath_targetXhasLabelXsoftwareXX': [(lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().has('name','marko').shortestPath().with_('~tinkerpop.shortestPath.target',__.hasLabel('software')))], 
+    'g_V_hasXname_markoX_shortestPath_targetXhasXname_joshXX_distanceXweightX': [(lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().has('name','marko').shortestPath().with_('~tinkerpop.shortestPath.target',__.has('name','josh')).with_('~tinkerpop.shortestPath.distance','weight'))], 
+    'g_V_hasXname_danielX_shortestPath_targetXhasXname_stephenXX_edgesXbothEXusesXX': [(lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().has('name','daniel').shortestPath().with_('~tinkerpop.shortestPath.target',__.has('name','stephen')).with_('~tinkerpop.shortestPath.edges',__.bothE('uses')))], 
+    'g_V_hasXsong_name_MIGHT_AS_WELLX_shortestPath_targetXhasXsong_name_MAYBE_YOU_KNOW_HOW_I_FEELXX_edgesXoutEXfollowedByXX_distanceXweightX': [(lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().has('song','name','MIGHT AS WELL').shortestPath().with_('~tinkerpop.shortestPath.target',__.has('song','name','MAYBE YOU KNOW HOW I FEEL')).with_('~tinkerpop.shortestPath.edges',__.outE('followedBy')).with_('~tinkerpop.shortestPath.distance','weight'))], 
+    'g_V_hasXname_markoX_shortestPath_maxDistanceX1X': [(lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().has('name','marko').shortestPath().with_('~tinkerpop.shortestPath.maxDistance',1))], 
+    'g_V_hasXname_vadasX_shortestPath_distanceXweightX_maxDistanceX1_3X': [(lambda g:g.withStrategies(*[TraversalStrategy('VertexProgramStrategy',{'graphComputer':'org.apache.tinkerpop.gremlin.process.computer.GraphComputer'}, 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy')]).V().has('name','vadas').shortestPath().with_('~tinkerpop.shortestPath.distance','weight').with_('~tinkerpop.shortestPath.maxDistance',float(1.3)))], 
+    'g_V_age_sum': [(lambda g:g.V().age.sum())], 
+    'g_V_foo_sum': [(lambda g:g.V().foo.sum())], 
+    'g_V_age_fold_sumXlocalX': [(lambda g:g.V().age.fold().sum(Scope.local))], 
+    'g_V_foo_fold_sumXlocalX': [(lambda g:g.V().foo.fold().sum(Scope.local))], 
+    'g_V_hasLabelXsoftwareX_group_byXnameX_byXbothE_weight_sumX': [(lambda g:g.V().hasLabel('software').group().by('name').by(__.bothE().weight.sum()))], 
+    'g_V_localXoutE_foldX_unfold': [(lambda g:g.V().local(__.outE().fold()).unfold())], 
+    'g_V_valueMap_unfold_mapXkeyX': [(lambda g, l1=None:g.V().valueMap().unfold().map(l1))], 
+    'g_VX1X_repeatXboth_simplePathX_untilXhasIdX6XX_path_byXnameX_unfold': [(lambda g, vid6=None,vid1=None:g.V(vid1).repeat(__.both().simplePath()).until(__.hasId(vid6)).path().by('name').unfold())], 
+    'g_V_valueMap': [(lambda g:g.V().valueMap())], 
+    'g_V_valueMapXtrueX': [(lambda g:g.V().valueMap(True))], 
+    'g_V_valueMap_withXtokensX': [(lambda g:g.V().valueMap().with_('~tinkerpop.valueMap.tokens'))], 
+    'g_V_valueMapXname_ageX': [(lambda g:g.V().valueMap('name','age'))], 
+    'g_V_valueMapXtrue_name_ageX': [(lambda g:g.V().valueMap(True,'name','age'))], 
+    'g_V_valueMapXname_ageX_withXtokensX': [(lambda g:g.V().valueMap('name','age').with_('~tinkerpop.valueMap.tokens'))], 
+    'g_V_valueMapXname_ageX_withXtokens_labelsX_byXunfoldX': [(lambda g:g.V().valueMap('name','age').with_('~tinkerpop.valueMap.tokens',2).by(__.unfold()))], 
+    'g_V_valueMapXname_ageX_withXtokens_idsX_byXunfoldX': [(lambda g:g.V().valueMap('name','age').with_('~tinkerpop.valueMap.tokens',1).by(__.unfold()))], 
+    'g_VX1X_outXcreatedX_valueMap': [(lambda g, vid1=None:g.V(vid1).out('created').valueMap())], 
+    'g_V_hasLabelXpersonX_filterXoutEXcreatedXX_valueMapXtrueX': [(lambda g:g.V().hasLabel('person').filter(__.outE('created')).valueMap(True))], 
+    'g_V_hasLabelXpersonX_filterXoutEXcreatedXX_valueMap_withXtokensX': [(lambda g:g.V().hasLabel('person').filter(__.outE('created')).valueMap().with_('~tinkerpop.valueMap.tokens'))], 
+    'g_VX1X_valueMapXname_locationX_byXunfoldX_by': [(lambda g, vid1=None:g.V(vid1).valueMap('name','location').by(__.unfold()).by())], 
+    'g_VXlistX1_2_3XX_name': [(lambda g, xx1=None:g.V(xx1).name)], 
+    'g_VXlistXv1_v2_v3XX_name': [(lambda g, xx1=None:g.V(xx1).name)], 
+    'g_V': [(lambda g:g.V())], 
+    'g_VXv1X_out': [(lambda g, v1=None:g.V(v1).out())], 
+    'g_VX1X_out': [(lambda g, vid1=None:g.V(vid1).out())], 
+    'g_VX2X_in': [(lambda g, vid2=None:g.V(vid2).in_())], 
+    'g_VX4X_both': [(lambda g, vid4=None:g.V(vid4).both())], 
+    'g_E': [(lambda g:g.E())], 
+    'g_EX11X': [(lambda g, eid11=None:g.E(eid11))], 
+    'g_EX11AsStringX': [(lambda g, eid11=None:g.E(eid11))], 
+    'g_EXe11X': [(lambda g, e11=None:g.E(e11))], 
+    'g_EXe7_e11X': [(lambda g, e7=None,e11=None:g.E(e7,e11))], 
+    'g_EXlistXe7_e11XX': [(lambda g, xx1=None:g.E(xx1))], 
+    'g_VX1X_outE': [(lambda g, vid1=None:g.V(vid1).outE())], 
+    'g_VX2X_outE': [(lambda g, vid2=None:g.V(vid2).inE())], 
+    'g_VX4X_bothEXcreatedX': [(lambda g, vid4=None:g.V(vid4).bothE('created'))], 
+    'g_VX4X_bothE': [(lambda g, vid4=None:g.V(vid4).bothE())], 
+    'g_VX1X_outE_inV': [(lambda g, vid1=None:g.V(vid1).both())], 
+    'g_VX2X_inE_outV': [(lambda g, vid2=None:g.V(vid2).inE().outV())], 
+    'g_V_outE_hasXweight_1X_outV': [(lambda g:g.V().outE().has('weight',float(1.0)).outV())], 
+    'g_V_out_outE_inV_inE_inV_both_name': [(lambda g:g.V().out().outE().inV().inE().inV().both().name)], 
+    'g_VX1X_outEXknowsX_bothV_name': [(lambda g, vid1=None:g.V(vid1).outE('knows').bothV().name)], 
+    'g_VX1X_outE_otherV': [(lambda g, vid1=None:g.V(vid1).outE().otherV())], 
+    'g_VX4X_bothE_otherV': [(lambda g, vid4=None:g.V(vid4).bothE().otherV())], 
+    'g_VX4X_bothE_hasXweight_lt_1X_otherV': [(lambda g, vid4=None:g.V(vid4).bothE().has('weight',P.lt(float(1.0))).otherV())], 
+    'g_VX2X_inE': [(lambda g, vid2=None:g.V(vid2).bothE())], 
+    'get_g_VX1X_outE_otherV': [(lambda g, vid1=None:g.V(vid1).outE().otherV())], 
+    'g_VX1X_outXknowsX': [(lambda g, vid1=None:g.V(vid1).out('knows'))], 
+    'g_VX1AsStringX_outXknowsX': [(lambda g, vid1=None:g.V(vid1).out('knows'))], 
+    'g_VX1X_outXknows_createdX': [(lambda g, vid1=None:g.V(vid1).out('knows','created'))], 
+    'g_VX1X_outEXknowsX_inV': [(lambda g, vid1=None:g.V(vid1).outE('knows').inV())], 
+    'g_VX1X_outEXknows_createdX_inV': [(lambda g, vid1=None:g.V(vid1).outE('knows','created').inV())], 
+    'g_V_out_out': [(lambda g:g.V().out().out())], 
+    'g_VX1X_out_out_out': [(lambda g, vid1=None:g.V(vid1).out().out().out())], 
+    'g_VX1X_out_name': [(lambda g, vid1=None:g.V(vid1).out().name)], 
+    'g_VX1X_to_XOUT_knowsX': [(lambda g, vid1=None:g.V(vid1).to(Direction.OUT,'knows'))], 
+    'g_VX1_2_3_4X_name': [(lambda g, vid4=None,vid3=None,vid2=None,vid1=None:g.V(vid1,vid2,vid3,vid4).name)], 
+    'g_V_hasLabelXpersonX_V_hasLabelXsoftwareX_name': [(lambda g:g.V().hasLabel('person').V().hasLabel('software').name)], 
+    'g_V_hasLabelXloopsX_bothEXselfX': [(lambda g:g.V().hasLabel('loops').bothE('self'))], 
+    'g_V_hasLabelXloopsX_bothXselfX': [(lambda g:g.V().hasLabel('loops').both('self'))], 
+    'g_V_valueXnameX_aggregateXxX_capXxX': [(lambda g:g.V().name.aggregate('x').cap('x'))], 
+    'g_V_valueXnameX_aggregateXglobal_xX_capXxX': [(lambda g:g.V().name.aggregate(Scope.global_,'x').cap('x'))], 
+    'g_V_aggregateXxX_byXnameX_capXxX': [(lambda g:g.V().aggregate('x').by('name').cap('x'))], 
+    'g_V_out_aggregateXaX_path': [(lambda g:g.V().out().aggregate('a').path())], 
+    'g_V_hasLabelXpersonX_aggregateXxX_byXageX_capXxX_asXyX_selectXyX': [(lambda g:g.V().hasLabel('person').aggregate('x').by('age').cap('x').as_('y').select('y'))], 
+    'g_V_aggregateXlocal_a_nameX_out_capXaX': [(lambda g:g.V().aggregate(Scope.local,'a').by('name').out().cap('a'))], 
+    'g_VX1X_aggregateXlocal_aX_byXnameX_out_aggregateXlocal_aX_byXnameX_name_capXaX': [(lambda g, vid1=None:g.V(vid1).aggregate(Scope.local,'a').by('name').out().aggregate(Scope.local,'a').by('name').name.cap('a'))], 
+    'g_withSideEffectXa_setX_V_both_name_aggregateXlocal_aX_capXaX': [(lambda g, xx1=None:g.withSideEffect('a',xx1).V().both().name.aggregate(Scope.local,'a').cap('a'))], 
+    'g_V_aggregateXlocal_aX_byXoutEXcreatedX_countX_out_out_aggregateXlocal_aX_byXinEXcreatedX_weight_sumX': [(lambda g:g.V().aggregate(Scope.local,'a').by(__.outE('created').count()).out().out().aggregate(Scope.local,'a').by(__.inE('created').weight.sum()).cap('a'))], 
+    'g_V_group_byXnameX': [(lambda g:g.V().group().by('name'))], 
+    'g_V_group_byXageX': [(lambda g:g.V().group().by('age'))], 
+    'g_V_group_byXnameX_by': [(lambda g:g.V().group().by('name').by())], 
+    'g_V_groupXaX_byXnameX_capXaX': [(lambda g:g.V().group('a').by('name').cap('a'))], 
+    'g_V_hasXlangX_groupXaX_byXlangX_byXnameX_out_capXaX': [(lambda g:g.V().has('lang').group('a').by('lang').by('name').out().cap('a'))], 
+    'g_V_hasXlangX_group_byXlangX_byXcountX': [(lambda g:g.V().has('lang').group().by('lang').by(__.count()))], 
+    'g_V_repeatXout_groupXaX_byXnameX_byXcountX_timesX2X_capXaX': [(lambda g:g.V().repeat(__.out().group('a').by('name').by(__.count())).times(2).cap('a'))], 
+    'g_V_group_byXoutE_countX_byXnameX': [(lambda g:g.V().group().by(__.outE().count()).by('name'))], 
+    'g_V_groupXaX_byXlabelX_byXoutE_weight_sumX_capXaX': [(lambda g:g.V().group('a').by(T.label).by(__.outE().weight.sum()).cap('a'))], 
+    'g_V_repeatXbothXfollowedByXX_timesX2X_group_byXsongTypeX_byXcountX': [(lambda g:g.V().repeat(__.both('followedBy')).times(2).group().by('songType').by(__.count()))], 
+    'g_V_repeatXbothXfollowedByXX_timesX2X_groupXaX_byXsongTypeX_byXcountX_capXaX': [(lambda g:g.V().repeat(__.both('followedBy')).times(2).group('a').by('songType').by(__.count()).cap('a'))], 
+    'g_V_group_byXname_substring_1X_byXconstantX1XX': [(lambda g, l1=None:g.V().group().by(l1).by(__.constant(1)))], 
+    'g_V_groupXaX_byXname_substring_1X_byXconstantX1XX_capXaX': [(lambda g, l1=None:g.V().group('a').by(l1).by(__.constant(1)).cap('a'))], 
+    'g_V_out_group_byXlabelX_selectXpersonX_unfold_outXcreatedX_name_limitX2X': [(lambda g:g.V().out().group().by(T.label).select('person').unfold().out('created').name[0:2])], 
+    'g_V_hasLabelXsongX_group_byXnameX_byXproperties_groupCount_byXlabelXX': [(lambda g:g.V().hasLabel('song').group().by('name').by(__.properties().groupCount().by(T.label)))], 
+    'g_V_hasLabelXsongX_groupXaX_byXnameX_byXproperties_groupCount_byXlabelXX_out_capXaX': [(lambda g:g.V().hasLabel('song').group('a').by('name').by(__.properties().groupCount().by(T.label)).out().cap('a'))], 
+    'g_V_outXfollowedByX_group_byXsongTypeX_byXbothE_group_byXlabelX_byXweight_sumXX': [(lambda g:g.V().out('followedBy').group().by('songType').by(__.bothE().group().by(T.label).by(__.weight.sum())))], 
+    'g_V_groupXmX_byXnameX_byXinXknowsX_nameX_capXmX': [(lambda g:g.V().group('m').by('name').by(__.in_('knows').name).cap('m'))], 
+    'g_V_group_byXlabelX_byXbothE_groupXaX_byXlabelX_byXweight_sumX_weight_sumX': [(lambda g:g.V().group().by(T.label).by(__.bothE().group('a').by(T.label).by(__.weight.sum()).weight.sum()))], 
+    'g_withSideEffectXa__marko_666_noone_blahX_V_groupXaX_byXnameX_byXoutE_label_foldX_capXaX': [(lambda g, xx1=None:g.withSideEffect('a',xx1).V().group('a').by('name').by(__.outE().label().fold()).cap('a'))], 
+    'g_V_hasLabelXpersonX_asXpX_outXcreatedX_group_byXnameX_byXselectXpX_valuesXageX_sumX': [(lambda g:g.V().hasLabel('person').as_('p').out('created').group().by('name').by(__.select('p').age.sum()))], 
+    'g_V_hasLabelXpersonX_asXpX_outXcreatedX_groupXaX_byXnameX_byXselectXpX_valuesXageX_sumX_capXaX': [(lambda g:g.V().hasLabel('person').as_('p').out('created').group('a').by('name').by(__.select('p').age.sum()).cap('a'))], 
+    'g_V_group_byXlabelX_byXlabel_countX': [(lambda g:g.V().group().by(__.label()).by(__.label().count()))], 
+    'g_V_groupXmX_byXlabelX_byXlabel_countX_capXmX': [(lambda g:g.V().group('m').by(__.label()).by(__.label().count()).cap('m'))], 
+    'g_V_outXcreatedX_groupCount_byXnameX': [(lambda g:g.V().out('created').groupCount().by('name'))], 
+    'g_V_outXcreatedX_name_groupCount': [(lambda g:g.V().out('created').name.groupCount())], 
+    'g_V_outXcreatedX_groupCountXaX_byXnameX_capXaX': [(lambda g:g.V().out('created').groupCount('a').by('name').cap('a'))], 
+    'g_V_outXcreatedX_name_groupCountXaX_capXaX': [(lambda g:g.V().out('created').name.groupCount('a').cap('a'))], 
+    'g_V_repeatXout_groupCountXaX_byXnameXX_timesX2X_capXaX': [(lambda g:g.V().repeat(__.out().groupCount('a').by('name')).times(2).cap('a'))], 
+    'g_V_both_groupCountXaX_byXlabelX_asXbX_barrier_whereXselectXaX_selectXsoftwareX_isXgtX2XXX_selectXbX_name': [(lambda g:g.V().both().groupCount('a').by(T.label).as_('b').barrier().where(__.select('a').select('software').is_(P.gt(2))).select('b').name)], 
+    'g_V_unionXoutXknowsX__outXcreatedX_inXcreatedXX_groupCount_selectXvaluesX_unfold_sum': [(lambda g:g.V().union(__.out('knows'),__.out('created').in_('created')).groupCount().select(Column.values).unfold().sum())], 
+    'g_V_hasXnoX_groupCount': [(lambda g:g.V().has('no').groupCount())], 
+    'g_V_hasXnoX_groupCountXaX_capXaX': [(lambda g:g.V().has('no').groupCount('a').cap('a'))], 
+    'g_V_unionXrepeatXoutX_timesX2X_groupCountXmX_byXlangXX__repeatXinX_timesX2X_groupCountXmX_byXnameXX_capXmX': [(lambda g:g.V().union(__.repeat(__.out()).times(2).groupCount('m').by('lang'),__.repeat(__.in_()).times(2).groupCount('m').by('name')).cap('m'))], 
+    'g_V_outXcreatedX_groupCountXxX_capXxX': [(lambda g:g.V().out('created').groupCount('x').cap('x'))], 
+    'g_V_groupCount_byXbothE_countX': [(lambda g:g.V().groupCount().by(__.bothE().count()))], 
+    'g_V_both_groupCountXaX_out_capXaX_selectXkeysX_unfold_both_groupCountXaX_capXaX': [(lambda g:g.V().both().groupCount('a').out().cap('a').select(Column.keys).unfold().both().groupCount('a').cap('a'))], 
+    'g_V_hasXperson_name_markoX_bothXknowsX_groupCount_byXvaluesXnameX_foldX': [(lambda g:g.V().has('person','name','marko').both('knows').groupCount().by(__.name.fold()))], 
+    'g_VX1X_out_injectXv2X_name': [(lambda g, vid1=None,v2=None:g.V(vid1).out().inject(v2).name)], 
+    'g_VX1X_out_name_injectXdanielX_asXaX_mapXlengthX_path': [(lambda g, l1=None,vid1=None:g.V(vid1).out().name.inject('daniel').as_('a').map(l1).path())], 
+    'g_VX1X_injectXg_VX4XX_out_name': [(lambda g, vid1=None,v4=None:g.V(vid1).inject(v4).out().name)], 
+    'g_injectXnull_1_3_nullX': [(lambda g:g.inject(None,1,3,None))], 
+    'g_injectX10_20_null_20_10_10X_groupCountXxX_dedup_asXyX_projectXa_bX_by_byXselectXxX_selectXselectXyXXX': [(lambda g:g.inject(10,20,None,20,10,10).groupCount('x').dedup().as_('y').project('a','b').by().by(__.select('x').select(__.select('y'))))], 
+    'g_injectXname_marko_age_nullX_selectXname_ageX': [(lambda g, xx1=None:g.inject(xx1).select('name','age'))], 
+    'g_io_readXkryoX': [(lambda g:g.io('data/tinkerpop-modern.kryo').read()), (lambda g:g.V()), (lambda g:g.E())], 
+    'g_io_read_withXreader_gryoX': [(lambda g:g.io('data/tinkerpop-modern.kryo').with_('~tinkerpop.io.reader','gryo').read()), (lambda g:g.V()), (lambda g:g.E())], 
+    'g_io_readXgraphsonX': [(lambda g:g.io('data/tinkerpop-modern.json').read()), (lambda g:g.V()), (lambda g:g.E())], 
+    'g_io_read_withXreader_graphsonX': [(lambda g:g.io('data/tinkerpop-modern.json').with_('~tinkerpop.io.reader','graphson').read()), (lambda g:g.V()), (lambda g:g.E())], 
+    'g_io_readXgraphmlX': [(lambda g:g.io('data/tinkerpop-modern.xml').read()), (lambda g:g.V()), (lambda g:g.E())], 
+    'g_io_read_withXreader_graphmlX': [(lambda g:g.io('data/tinkerpop-modern.xml').with_('~tinkerpop.io.reader','graphml').read()), (lambda g:g.V()), (lambda g:g.E())], 
+    'g_withSackXhelloX_V_outE_sackXassignX_byXlabelX_inV_sack': [(lambda g:g.withSack('hello').V().outE().sack(Operator.assign).by(T.label).inV().sack())], 
+    'g_withSackX0X_V_outE_sackXsumX_byXweightX_inV_sack_sum': [(lambda g:g.withSack(float(0.0)).V().outE().sack(Operator.sum).by('weight').inV().sack().sum())], 
+    'g_withSackX0X_V_repeatXoutE_sackXsumX_byXweightX_inVX_timesX2X_sack': [(lambda g:g.withSack(float(0.0)).V().repeat(__.outE().sack(Operator.sum).by('weight').inV()).times(2).sack())], 
+    'g_withBulkXfalseX_withSackX1_sumX_VX1X_localXoutEXknowsX_barrierXnormSackX_inVX_inXknowsX_barrier_sack': [(lambda g, vid1=None:g.withBulk(False).withSack(float(1.0),Operator.sum).V(vid1).local(__.outE('knows').barrier(Barrier.normSack).inV()).in_('knows').barrier().sack())], 
+    'g_withBulkXfalseX_withSackX1_sumX_V_out_barrier_sack': [(lambda g:g.withBulk(False).withSack(1,Operator.sum).V().out().barrier().sack())], 
+    'g_withSackX1_sumX_VX1X_localXoutXknowsX_barrierXnormSackXX_inXknowsX_barrier_sack': [(lambda g, vid1=None:g.withSack(float(1.0),Operator.sum).V(vid1).local(__.out('knows').barrier(Barrier.normSack)).in_('knows').barrier().sack())], 
+    'g_V_hasXageX_groupCountXaX_byXnameX_out_capXaX': [(lambda g:g.V().has('age').groupCount('a').by('name').out().cap('a'))], 
+    'g_V_storeXa_nameX_out_capXaX': [(lambda g:g.V().store('a').by('name').out().cap('a'))], 
+    'g_VX1X_storeXaX_byXnameX_out_storeXaX_byXnameX_name_capXaX': [(lambda g, vid1=None:g.V(vid1).store('a').by('name').out().store('a').by('name').name.cap('a'))], 
+    'g_withSideEffectXa_setX_V_both_name_storeXaX_capXaX': [(lambda g, xx1=None:g.withSideEffect('a',xx1).V().both().name.store('a').cap('a'))], 
+    'g_V_storeXaX_byXoutEXcreatedX_countX_out_out_storeXaX_byXinEXcreatedX_weight_sumX': [(lambda g:g.V().store('a').by(__.outE('created').count()).out().out().store('a').by(__.inE('created').weight.sum()).cap('a'))], 
+}
diff --git a/gremlin-python/src/main/python/radish/terrain.py b/gremlin-python/src/main/python/radish/terrain.py
new file mode 100644
index 0000000..24a102c
--- /dev/null
+++ b/gremlin-python/src/main/python/radish/terrain.py
@@ -0,0 +1,98 @@
+#
+# 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.
+#
+
+from gremlin_python.process.anonymous_traversal import traversal
+from gremlin_python.process.graph_traversal import __
+from gremlin_python.driver import serializer
+from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection
+from radish import before, after, world
+
+outV = __.outV
+label = __.label
+inV = __.inV
+project = __.project
+tail = __.tail
+
+
+@before.all
+def prepare_static_traversal_source(features, marker):
+    # as the various traversal sources for testing do not change their data, there is no need to re-create remotes
+    # and client side lookup data over and over. it can be created once for all tests and be reused.
+    cache = {}
+    for graph_name in (("modern", "gmodern"), ("classic", "gclassic"), ("crew", "gcrew"), ("grateful", "ggrateful"), ("sink", "gsink")):
+        cache[graph_name[0]] = {}
+        remote = __create_remote(graph_name[1])
+        cache[graph_name[0]]["remote_conn"] = __create_remote(graph_name[1])
+        cache[graph_name[0]]["lookup_v"] = world.create_lookup_v(remote)
+        cache[graph_name[0]]["lookup_e"] = world.create_lookup_e(remote)
+
+    # store the cache on the global context so that remotes can be shutdown cleanly at the end of the tests
+    world.cache = cache
+
+    # iterate each feature and apply the cached remotes/lookups to each scenario context so that they are
+    # accessible to the feature steps for test logic
+    for feature in features:
+        for scenario in feature.all_scenarios:
+            scenario.context.remote_conn = {}
+            scenario.context.lookup_v = {}
+            scenario.context.lookup_e = {}
+
+            for graph_name in ("modern", "classic", "crew", "grateful", "sink"):
+                scenario.context.remote_conn[graph_name] = cache[graph_name]["remote_conn"]
+                scenario.context.lookup_v[graph_name] = cache[graph_name]["lookup_v"]
+                scenario.context.lookup_e[graph_name] = cache[graph_name]["lookup_e"]
+
+            # setup the "empty" lookups as needed
+            scenario.context.lookup_v["empty"] = {}
+            scenario.context.lookup_e["empty"] = {}
+
+
+@before.each_scenario
+def prepare_traversal_source(scenario):
+    # some tests create data - create a fresh remote to the empty graph and clear that graph prior to each test
+    remote = __create_remote("ggraph")
+    scenario.context.remote_conn["empty"] = remote
+    scenario.context.traversals = world.gremlins.get(scenario.sentence, None)
+    g = traversal().withRemote(remote)
+    g.V().drop().iterate()
+
+
+@after.each_scenario
+def close_traversal_source(scenario):
+    scenario.context.remote_conn["empty"].close()
+
+
+@after.all
+def close_static_traversal_source(features, marker):
+    for key, value in world.cache.items():
+        value["remote_conn"].close()
+
+
+def __create_remote(server_graph_name):
+    if not("serializer" in world.config.user_data):
+        raise ValueError('test configuration requires setting of --user-data="serializer={mime-type}"')
+
+    if world.config.user_data["serializer"] == "application/vnd.gremlin-v3.0+json":
+        s = serializer.GraphSONSerializersV3d0()
+    elif world.config.user_data["serializer"] == "application/vnd.graphbinary-v1.0":
+        s = serializer.GraphBinarySerializersV1()
+    else:
+        raise ValueError('serializer not found - ' + world.config.user_data["serializer"])
+
+    return DriverRemoteConnection('ws://localhost:45940/gremlin', server_graph_name, message_serializer=s)
diff --git a/gremlin-python/src/main/python/radish/utils.py b/gremlin-python/src/main/python/radish/utils.py
new file mode 100644
index 0000000..09e565c
--- /dev/null
+++ b/gremlin-python/src/main/python/radish/utils.py
@@ -0,0 +1,40 @@
+#
+# 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.
+#
+
+from gremlin_python.process.anonymous_traversal import traversal
+from gremlin_python.process.graph_traversal import __
+from radish import pick
+
+@pick
+def create_lookup_v(remote):
+    g = traversal().withRemote(remote)
+
+    # hold a map of name/vertex for use in asserting results
+    return g.V().group().by('name').by(__.tail()).next()
+
+
+@pick
+def create_lookup_e(remote):
+    g = traversal().withRemote(remote)
+
+    # hold a map of the "name"/edge for use in asserting results - "name" in this context is in the form of
+    # outgoingV-label->incomingV
+    return g.E().group(). \
+        by(lambda: ("it.outVertex().value('name') + '-' + it.label() + '->' + it.inVertex().value('name')", "gremlin-groovy")). \
+        by(__.tail()).next()
\ No newline at end of file
diff --git a/gremlin-python/src/main/jython/setup.cfg b/gremlin-python/src/main/python/setup.cfg
similarity index 100%
rename from gremlin-python/src/main/jython/setup.cfg
rename to gremlin-python/src/main/python/setup.cfg
diff --git a/gremlin-python/src/main/python/setup.py b/gremlin-python/src/main/python/setup.py
new file mode 100644
index 0000000..af4e970
--- /dev/null
+++ b/gremlin-python/src/main/python/setup.py
@@ -0,0 +1,93 @@
+"""
+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.
+"""
+import codecs
+import os
+import sys
+import time
+from setuptools import setup
+
+# Folder containing the setup.py
+root = os.path.dirname(os.path.abspath(__file__))
+
+# Path to __version__ module
+version_file = os.path.join(root, 'gremlin_python', '__version__.py')
+
+# Check if this is a source distribution.
+# If not create the __version__ module containing the version
+if not os.path.exists(os.path.join(root, 'PKG-INFO')):
+    timestamp = int(os.getenv('TIMESTAMP', time.time() * 1000)) / 1000
+    fd = codecs.open(version_file, 'w', 'utf-8')
+    fd.write("'''")
+    fd.write(__doc__)
+    fd.write("'''\n")
+    fd.write('version   = %r\n' % os.getenv('VERSION', '?').replace('-SNAPSHOT', '.dev-%d' % timestamp))
+    fd.write('timestamp = %d\n' % timestamp)
+    fd.close()
+# Load version
+from gremlin_python import __version__
+
+version = __version__.version
+
+install_requires = [
+    'nest_asyncio',
+    'aiohttp>=3.7.0,<=3.7.4',
+    'aenum>=1.4.5,<3.0.0',
+    'six>=1.10.0,<2.0.0',
+    'isodate>=0.6.0,<1.0.0',
+    'pyparsing>=2.4.7,<3.0.0'
+]
+
+if sys.version_info < (3, 5):
+    install_requires += ['pyparsing>=2.4.6,<3.0.0']
+
+setup(
+    name='gremlinpython',
+    version=version,
+    packages=['gremlin_python', 'gremlin_python.driver',
+              'gremlin_python.driver.aiohttp', 'gremlin_python.process',
+              'gremlin_python.structure', 'gremlin_python.structure.io'],
+    license='Apache 2',
+    url='http://tinkerpop.apache.org',
+    description='Gremlin-Python for Apache TinkerPop',
+    long_description=codecs.open("README.rst", "r", "UTF-8").read(),
+    long_description_content_type='text/x-rst',
+    test_suite="tests",
+    data_files=[("", ["LICENSE", "NOTICE"])],
+    setup_requires=[
+        'pytest-runner==5.2',
+        'importlib-metadata<3.0.0'
+    ],
+    tests_require=[
+        'pytest>=4.6.4,<5.0.0',
+        'mock>=3.0.5,<4.0.0',
+        'radish-bdd==0.8.6',
+        'PyHamcrest>=1.9.0,<2.0.0'
+    ],
+    install_requires=install_requires,
+    extra_require={
+        'kerberos': 'kerberos>=1.3.0,<2.0.0'    # Does not install in Microsoft Windows
+    },
+    classifiers=[
+        "Intended Audience :: Developers",
+        "License :: OSI Approved :: Apache Software License",
+        "Natural Language :: English",
+        "Programming Language :: Python :: 3.5",
+        "Programming Language :: Python :: 3.6",
+    ]
+)
diff --git a/gremlin-python/src/main/jython/tests/__init__.py b/gremlin-python/src/main/python/tests/__init__.py
similarity index 100%
rename from gremlin-python/src/main/jython/tests/__init__.py
rename to gremlin-python/src/main/python/tests/__init__.py
diff --git a/gremlin-python/src/main/python/tests/conftest.py b/gremlin-python/src/main/python/tests/conftest.py
new file mode 100644
index 0000000..4f20a44
--- /dev/null
+++ b/gremlin-python/src/main/python/tests/conftest.py
@@ -0,0 +1,176 @@
+#
+# 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.
+#
+
+import concurrent.futures
+import ssl
+import pytest
+import sys
+import socket
+
+from six.moves import queue
+
+from gremlin_python.driver.client import Client
+from gremlin_python.driver.connection import Connection
+from gremlin_python.driver import serializer
+from gremlin_python.driver.driver_remote_connection import (
+    DriverRemoteConnection)
+from gremlin_python.driver.protocol import GremlinServerWSProtocol
+from gremlin_python.driver.serializer import (
+    GraphSONMessageSerializer, GraphSONSerializersV2d0, GraphSONSerializersV3d0,
+    GraphBinarySerializersV1)
+from gremlin_python.driver.aiohttp.transport import AiohttpTransport
+
+gremlin_server_url = 'ws://localhost:{}/gremlin'
+anonymous_url = gremlin_server_url.format(45940)
+basic_url = 'wss://localhost:{}/gremlin'.format(45941)
+kerberos_url = gremlin_server_url.format(45942)
+kerberized_service = 'test-service@{}'.format(socket.gethostname())
+
+
+@pytest.fixture
+def connection(request):
+    protocol = GremlinServerWSProtocol(
+        GraphSONMessageSerializer(),
+        username='stephen', password='password')
+    executor = concurrent.futures.ThreadPoolExecutor(5)
+    pool = queue.Queue()
+    try:
+        conn = Connection(anonymous_url, 'gmodern', protocol,
+                          lambda: AiohttpTransport(), executor, pool)
+    except OSError:
+        executor.shutdown()
+        pytest.skip('Gremlin Server is not running')
+    else:
+        def fin():
+            executor.shutdown()
+            conn.close()
+        request.addfinalizer(fin)
+        return conn
+
+
+@pytest.fixture
+def client(request):
+    try:
+        client = Client(anonymous_url, 'gmodern')
+    except OSError:
+        pytest.skip('Gremlin Server is not running')
+    else:
+        def fin():
+            client.close()
+        request.addfinalizer(fin)
+        return client
+
+
+@pytest.fixture(params=['basic', 'kerberos'])
+def authenticated_client(request):
+    try:
+        if request.param == 'basic':
+            # turn off certificate verification for testing purposes only
+            ssl_opts = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
+            ssl_opts.verify_mode = ssl.CERT_NONE
+            client = Client(basic_url, 'gmodern', username='stephen', password='password',
+                            transport_factory=lambda: AiohttpTransport(ssl_options=ssl_opts))
+        elif request.param == 'kerberos':
+            client = Client(kerberos_url, 'gmodern', kerberized_service=kerberized_service)
+        else:
+            raise ValueError("Invalid authentication option - " + request.param)
+    except OSError:
+        pytest.skip('Gremlin Server is not running')
+    else:
+        def fin():
+            client.close()
+        request.addfinalizer(fin)
+        return client
+
+
+@pytest.fixture(params=['graphsonv2', 'graphsonv3', 'graphbinaryv1'])
+def remote_connection(request):
+    try:
+        if request.param == 'graphbinaryv1':
+            remote_conn = DriverRemoteConnection(anonymous_url, 'gmodern',
+                                                 message_serializer=serializer.GraphBinarySerializersV1())
+        elif request.param == 'graphsonv2':
+            remote_conn = DriverRemoteConnection(anonymous_url, 'gmodern',
+                                                 message_serializer=serializer.GraphSONSerializersV2d0())
+        elif request.param == 'graphsonv3':
+            remote_conn = DriverRemoteConnection(anonymous_url, 'gmodern',
+                                                 message_serializer=serializer.GraphSONSerializersV3d0())
+        else:
+            raise ValueError("Invalid serializer option - " + request.param)
+    except OSError:
+        pytest.skip('Gremlin Server is not running')
+    else:
+        def fin():
+            remote_conn.close()
+        request.addfinalizer(fin)
+        return remote_conn
+
+
+@pytest.fixture(params=['basic', 'kerberos'])
+def remote_connection_authenticated(request):
+    try:
+        if request.param == 'basic':
+            # turn off certificate verification for testing purposes only
+            ssl_opts = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
+            ssl_opts.verify_mode = ssl.CERT_NONE
+            remote_conn = DriverRemoteConnection(basic_url, 'gmodern',
+                                                 username='stephen', password='password',
+                                                 message_serializer=serializer.GraphSONSerializersV2d0(),
+                                                 transport_factory=lambda: AiohttpTransport(ssl_options=ssl_opts))
+        elif request.param == 'kerberos':
+            remote_conn = DriverRemoteConnection(kerberos_url, 'gmodern', kerberized_service=kerberized_service,
+                                                 message_serializer=serializer.GraphSONSerializersV2d0())
+        else:
+            raise ValueError("Invalid authentication option - " + request.param)
+    except OSError:
+        pytest.skip('Gremlin Server is not running')
+    else:
+        def fin():
+            remote_conn.close()
+        request.addfinalizer(fin)
+        return remote_conn
+
+
+@pytest.fixture
+def remote_connection_graphsonV2(request):
+    try:
+        remote_conn = DriverRemoteConnection(anonymous_url, 'g',
+                                             message_serializer=serializer.GraphSONSerializersV2d0())
+    except OSError:
+        pytest.skip('Gremlin Server is not running')
+    else:
+        def fin():
+            remote_conn.close()
+        request.addfinalizer(fin)
+        return remote_conn
+
+
+@pytest.fixture
+def graphson_serializer_v2(request):
+    return GraphSONSerializersV2d0()
+
+
+@pytest.fixture
+def graphson_serializer_v3(request):
+    return GraphSONSerializersV3d0()
+
+
+@pytest.fixture
+def graphbinary_serializer_v1(request):
+    return GraphBinarySerializersV1()
diff --git a/gremlin-python/src/main/jython/tests/driver/__init__.py b/gremlin-python/src/main/python/tests/driver/__init__.py
similarity index 100%
rename from gremlin-python/src/main/jython/tests/driver/__init__.py
rename to gremlin-python/src/main/python/tests/driver/__init__.py
diff --git a/gremlin-python/src/main/python/tests/driver/test_client.py b/gremlin-python/src/main/python/tests/driver/test_client.py
new file mode 100644
index 0000000..ac96642
--- /dev/null
+++ b/gremlin-python/src/main/python/tests/driver/test_client.py
@@ -0,0 +1,389 @@
+#
+# 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.
+#
+import asyncio
+import threading
+import uuid
+
+from gremlin_python.driver.client import Client
+from gremlin_python.driver.protocol import GremlinServerError
+from gremlin_python.driver.request import RequestMessage
+from gremlin_python.process.graph_traversal import __
+from gremlin_python.process.strategies import OptionsStrategy
+from gremlin_python.structure.graph import Graph
+from gremlin_python.driver.aiohttp.transport import AiohttpTransport
+from asyncio import TimeoutError
+
+__author__ = 'David M. Brown (davebshow@gmail.com)'
+
+
+def test_connection(connection):
+    g = Graph().traversal()
+    t = g.V()
+    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'gmodern'}})
+    results_set = connection.write(message).result()
+    future = results_set.all()
+    results = future.result()
+    assert len(results) == 6
+    assert isinstance(results, list)
+    assert results_set.done.done()
+    assert 'host' in results_set.status_attributes
+
+
+def test_client_message_too_big(client):
+    try:
+        client = Client("http://localhost", 'g', max_content_length=1024)
+        client.submit("1+1").all().result()
+        assert False
+    except Exception:
+        assert True
+    finally:
+        client.close()
+
+
+def test_client_simple_eval(client):
+    assert client.submit('1 + 1').all().result()[0] == 2
+
+
+def test_client_simple_eval_bindings(client):
+    assert client.submit('x + x', {'x': 2}).all().result()[0] == 4
+
+
+def test_client_eval_traversal(client):
+    assert len(client.submit('g.V()').all().result()) == 6
+
+
+def test_client_error(client):
+    try:
+        # should fire an exception
+        client.submit('1/0').all().result()
+        assert False
+    except GremlinServerError as ex:
+        assert 'exceptions' in ex.status_attributes
+        assert 'stackTrace' in ex.status_attributes
+
+
+def test_client_connection_pool_after_error(client):
+    # Overwrite fixture with pool_size=1 client
+    client = Client('ws://localhost:45940/gremlin', 'gmodern', pool_size=1)
+
+    try:
+        # should fire an exception
+        client.submit('1/0').all().result()
+        assert False
+    except GremlinServerError as gse:
+        # expecting the pool size to be 1 again after query returned
+        assert gse.status_code == 597
+        assert client.available_pool_size == 1
+
+
+def test_client_side_timeout_set_for_aiohttp(client):
+    client = Client('ws://localhost:45940/gremlin', 'gmodern',
+                    transport_factory=lambda: AiohttpTransport(read_timeout=1, write_timeout=1))
+
+    try:
+        # should fire an exception
+        client.submit('Thread.sleep(2000);1').all().result()
+        assert False
+    except TimeoutError as err:
+        # asyncio TimeoutError has no message.
+        assert str(err) == ""
+
+
+async def async_connect(enable):
+    try:
+        transport = AiohttpTransport(call_from_event_loop=enable)
+        transport.connect('ws://localhost:45940/gremlin')
+        transport.close()
+        return True
+    except RuntimeError:
+        return False
+
+
+def test_from_event_loop():
+    assert not asyncio.get_event_loop().run_until_complete(async_connect(False))
+    assert asyncio.get_event_loop().run_until_complete(async_connect(True))
+
+
+def test_client_bytecode(client):
+    g = Graph().traversal()
+    t = g.V()
+    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'gmodern'}})
+    result_set = client.submit(message)
+    assert len(result_set.all().result()) == 6
+
+
+def test_client_bytecode_options(client):
+    # smoke test to validate serialization of OptionsStrategy. no way to really validate this from an integration
+    # test perspective because there's no way to access the internals of the strategy via bytecode
+    g = Graph().traversal()
+    t = g.withStrategies(OptionsStrategy(options={"x": "test", "y": True})).V()
+    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'gmodern'}})
+    result_set = client.submit(message)
+    assert len(result_set.all().result()) == 6
+    ##
+    t = g.with_("x", "test").with_("y", True).V()
+    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'gmodern'}})
+    result_set = client.submit(message)
+    assert len(result_set.all().result()) == 6
+
+
+def test_client_message_too_big(client):
+    try:
+        client = Client("http://localhost", 'g', max_content_length=1024)
+        client.submit("1+1").all().result()
+        assert False
+    except Exception:
+        assert True
+    finally:
+        client.close()
+
+
+def test_iterate_result_set(client):
+    g = Graph().traversal()
+    t = g.V()
+    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'gmodern'}})
+    result_set = client.submit(message)
+    results = []
+    for result in result_set:
+        results += result
+    assert len(results) == 6
+
+
+def test_client_async(client):
+    g = Graph().traversal()
+    t = g.V()
+    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'gmodern'}})
+    future = client.submitAsync(message)
+    result_set = future.result()
+    assert len(result_set.all().result()) == 6
+
+
+def test_connection_share(client):
+    # Overwrite fixture with pool_size=1 client
+    client = Client('ws://localhost:45940/gremlin', 'gmodern', pool_size=1)
+    g = Graph().traversal()
+    t = g.V()
+    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'gmodern'}})
+    message2 = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'gmodern'}})
+    future = client.submitAsync(message)
+    future2 = client.submitAsync(message2)
+
+    result_set2 = future2.result()
+    assert len(result_set2.all().result()) == 6
+
+    # This future has to finish for the second to yield result - pool_size=1
+    assert future.done()
+    result_set = future.result()
+    assert len(result_set.all().result()) == 6
+
+
+def test_multi_conn_pool(client):
+    g = Graph().traversal()
+    t = g.V()
+    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'gmodern'}})
+    message2 = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'gmodern'}})
+    client = Client('ws://localhost:45940/gremlin', 'g', pool_size=1)
+    future = client.submitAsync(message)
+    future2 = client.submitAsync(message2)
+
+    result_set2 = future2.result()
+    assert len(result_set2.all().result()) == 6
+
+    # with connection pool `future` may or may not be done here
+    result_set = future.result()
+    assert len(result_set.all().result()) == 6
+
+
+def test_multi_thread_pool(client):
+    g = Graph().traversal()
+    traversals = [g.V(),
+                  g.V().count(),
+                  g.E(),
+                  g.E().count()
+                  ]
+    results = [[] for _ in traversals]
+
+    # Use a condition variable to synchronise a group of threads, which should also inject some
+    # non-determinism into the run-time execution order
+    condition = threading.Condition()
+
+    def thread_run(tr, result_list):
+        message = RequestMessage('traversal', 'bytecode', {'gremlin': tr.bytecode, 'aliases': {'g': 'gmodern'}})
+        with condition:
+            condition.wait(5)
+        result_set = client.submit(message)
+        for result in result_set:
+            result_list.append(result)
+
+    threads = []
+    for i in range(len(results)):
+        thread = threading.Thread(target=thread_run,
+                                  args=(traversals[i], results[i]),
+                                  name="test_multi_thread_pool_%d" % i)
+        thread.daemon = True
+        threads.append(thread)
+        thread.start()
+    with condition:
+        condition.notify_all()
+
+    for t in threads:
+        t.join(5)
+
+    assert len(results[0][0]) == 6
+    assert results[1][0][0].object == 6
+    assert len(results[2][0]) == 6
+    assert results[3][0][0].object == 6
+
+
+def test_client_bytecode_with_int(client):
+    g = Graph().traversal()
+    t = g.V().has('age', 851401972585122).count()
+    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'gmodern'}})
+    result_set = client.submit(message)
+    results = []
+    for result in result_set:
+        results += result
+    assert len(results) == 1
+
+
+def test_multi_request_in_session(client):
+    # Overwrite fixture with session client
+    session_id = str(uuid.uuid4())
+    client = Client('ws://localhost:45940/gremlin', 'g', session=session_id)
+
+    assert client.submit('x = 1').all().result()[0] == 1
+    assert client.submit('x + 2').all().result()[0] == 3
+
+    client.close()
+
+    # attempt reconnect to session and make sure "x" is no longer a thing
+    client = Client('ws://localhost:45940/gremlin', 'g', session=session_id)
+    try:
+        # should fire an exception
+        client.submit('x').all().result()
+        assert False
+    except Exception:
+        assert True
+
+
+def test_client_pool_in_session(client):
+    # Overwrite fixture with pool_size=2 client
+    try:
+        # should fire an exception
+        client = Client('ws://localhost:45940/gremlin', 'g', session=str(uuid.uuid4()), pool_size=2)
+        assert False
+    except Exception:
+        assert True
+
+
+def test_big_result_set(client):
+    g = Graph().traversal()
+    t = g.inject(1).repeat(__.addV('person').property('name', __.loops())).times(20000).count()
+    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'g'}})
+    result_set = client.submit(message)
+    results = []
+    for result in result_set:
+        results += result
+    assert len(results) == 1
+
+    t = g.V().limit(10)
+    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'g'}})
+    result_set = client.submit(message)
+    results = []
+    for result in result_set:
+        results += result
+    assert len(results) == 10
+
+    t = g.V().limit(100)
+    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'g'}})
+    result_set = client.submit(message)
+    results = []
+    for result in result_set:
+        results += result
+    assert len(results) == 100
+
+    t = g.V().limit(1000)
+    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'g'}})
+    result_set = client.submit(message)
+    results = []
+    for result in result_set:
+        results += result
+    assert len(results) == 1000
+
+    t = g.V().limit(10000)
+    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'g'}})
+    result_set = client.submit(message)
+    results = []
+    for result in result_set:
+        results += result
+    assert len(results) == 10000
+
+
+def test_big_result_set_secure(authenticated_client):
+    g = Graph().traversal()
+    t = g.inject(1).repeat(__.addV('person').property('name', __.loops())).times(20000).count()
+    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'g'}})
+    result_set = authenticated_client.submit(message)
+    results = []
+    for result in result_set:
+        results += result
+    assert len(results) == 1
+
+    t = g.V().limit(10)
+    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'g'}})
+    result_set = authenticated_client.submit(message)
+    results = []
+    for result in result_set:
+        results += result
+    assert len(results) == 10
+
+    t = g.V().limit(100)
+    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'g'}})
+    result_set = authenticated_client.submit(message)
+    results = []
+    for result in result_set:
+        results += result
+    assert len(results) == 100
+
+    t = g.V().limit(1000)
+    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'g'}})
+    result_set = authenticated_client.submit(message)
+    results = []
+    for result in result_set:
+        results += result
+    assert len(results) == 1000
+
+    t = g.V().limit(10000)
+    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'g'}})
+    result_set = authenticated_client.submit(message)
+    results = []
+    for result in result_set:
+        results += result
+    assert len(results) == 10000
+
+
+async def asyncio_func():
+    return 1
+
+
+def test_asyncio(client):
+    try:
+        asyncio.get_event_loop().run_until_complete(asyncio_func())
+    except RuntimeError:
+        assert False
diff --git a/gremlin-python/src/main/python/tests/driver/test_driver_remote_connection.py b/gremlin-python/src/main/python/tests/driver/test_driver_remote_connection.py
new file mode 100644
index 0000000..4c95509
--- /dev/null
+++ b/gremlin-python/src/main/python/tests/driver/test_driver_remote_connection.py
@@ -0,0 +1,229 @@
+#
+# 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.
+#
+
+import pytest
+
+from gremlin_python import statics
+from gremlin_python.driver.protocol import GremlinServerError
+from gremlin_python.statics import long
+from gremlin_python.process.traversal import Traverser
+from gremlin_python.process.traversal import TraversalStrategy
+from gremlin_python.process.traversal import Bindings
+from gremlin_python.process.traversal import P, Order, T
+from gremlin_python.process.graph_traversal import __
+from gremlin_python.process.anonymous_traversal import traversal
+from gremlin_python.structure.graph import Vertex
+from gremlin_python.process.strategies import SubgraphStrategy, ReservedKeysVerificationStrategy, SeedStrategy
+from gremlin_python.structure.io.util import HashableDict
+from gremlin_python.driver.serializer import GraphSONSerializersV2d0
+
+__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
+
+
+class TestDriverRemoteConnection(object):
+    def test_traversals(self, remote_connection):
+        statics.load_statics(globals())
+        g = traversal().withRemote(remote_connection)
+
+        assert long(6) == g.V().count().toList()[0]
+        # #
+        assert Vertex(1) == g.V(1).next()
+        assert 1 == g.V(1).id().next()
+        assert Traverser(Vertex(1)) == g.V(1).nextTraverser()
+        assert 1 == len(g.V(1).toList())
+        assert isinstance(g.V(1).toList(), list)
+        results = g.V().repeat(out()).times(2).name
+        results = results.toList()
+        assert 2 == len(results)
+        assert "lop" in results
+        assert "ripple" in results
+        # #
+        assert 10 == g.V().repeat(both()).times(5)[0:10].count().next()
+        assert 1 == g.V().repeat(both()).times(5)[0:1].count().next()
+        assert 0 == g.V().repeat(both()).times(5)[0:0].count().next()
+        assert 4 == g.V()[2:].count().next()
+        assert 2 == g.V()[:2].count().next()
+        # #
+        results = g.withSideEffect('a', ['josh', 'peter']).V(1).out('created').in_('created').values('name').where(P.within('a')).toList()
+        assert 2 == len(results)
+        assert 'josh' in results
+        assert 'peter' in results
+        # #
+        results = g.V().out().profile().toList()
+        assert 1 == len(results)
+        assert 'metrics' in results[0]
+        assert 'dur' in results[0]
+        # #
+        results = g.V().has('name', 'peter').as_('a').out('created').as_('b').select('a', 'b').by(
+            __.valueMap()).toList()
+        assert 1 == len(results)
+        assert 'peter' == results[0]['a']['name'][0]
+        assert 35 == results[0]['a']['age'][0]
+        assert 'lop' == results[0]['b']['name'][0]
+        assert 'java' == results[0]['b']['lang'][0]
+        assert 2 == len(results[0]['a'])
+        assert 2 == len(results[0]['b'])
+        # #
+        results = g.V(1).inject(g.V(2).next()).values('name').toList()
+        assert 2 == len(results)
+        assert 'marko' in results
+        assert 'vadas' in results
+        # #
+        results = g.V().has('person', 'name', 'marko').map(lambda: ("it.get().value('name')", "gremlin-groovy")).toList()
+        assert 1 == len(results)
+        assert 'marko' in results
+        # #
+        # this test just validates that the underscored versions of steps conflicting with Gremlin work
+        # properly and can be removed when the old steps are removed - TINKERPOP-2272
+        results = g.V().filter_(__.values('age').sum_().and_(
+            __.max_().is_(gt(0)), __.min_().is_(gt(0)))).range_(0, 1).id_().next()
+        assert 1 == results
+        # #
+        # test binding in P
+        results = g.V().has('person', 'age', Bindings.of('x', lt(30))).count().next()
+        assert 2 == results
+        # #
+        # test dict keys which can only work on GraphBinary and GraphSON3 which include specific serialization
+        # types for dict
+        if not isinstance(remote_connection._client._message_serializer, GraphSONSerializersV2d0):
+            results = g.V().has('person', 'name', 'marko').elementMap("name").groupCount().next()
+            assert {HashableDict.of({T.id: 1, T.label: 'person', 'name': 'marko'}): 1} == results
+        if not isinstance(remote_connection._client._message_serializer, GraphSONSerializersV2d0):
+            results = g.V().has('person', 'name', 'marko').both('knows').groupCount().by(__.values('name').fold()).next()
+            assert {tuple(['vadas']): 1, tuple(['josh']): 1} == results
+
+    def test_lambda_traversals(self, remote_connection):
+        statics.load_statics(globals())
+        assert "remoteconnection[ws://localhost:45940/gremlin,gmodern]" == str(remote_connection)
+        g = traversal().withRemote(remote_connection)
+
+        assert 24.0 == g.withSack(1.0, lambda: ("x -> x + 1", "gremlin-groovy")).V().both().sack().sum().next()
+        assert 24.0 == g.withSack(lambda: ("{1.0d}", "gremlin-groovy"), lambda: ("x -> x + 1", "gremlin-groovy")).V().both().sack().sum().next()
+
+        assert 48.0 == g.withSack(1.0, lambda: ("x, y ->  x + y + 1", "gremlin-groovy")).V().both().sack().sum().next()
+        assert 48.0 == g.withSack(lambda: ("{1.0d}", "gremlin-groovy"), lambda: ("x, y ->  x + y + 1", "gremlin-groovy")).V().both().sack().sum().next()
+
+    def test_iteration(self, remote_connection):
+        statics.load_statics(globals())
+        g = traversal().withRemote(remote_connection)
+
+        t = g.V().count()
+        assert t.hasNext()
+        assert t.hasNext()
+        assert t.hasNext()
+        assert t.hasNext()
+        assert t.hasNext()
+        assert 6 == t.next()
+        assert not(t.hasNext())
+        assert not(t.hasNext())
+        assert not(t.hasNext())
+        assert not(t.hasNext())
+        assert not(t.hasNext())
+
+        t = g.V().has('name', P.within('marko', 'peter')).values('name').order()
+        assert "marko" == t.next()
+        assert t.hasNext()
+        assert t.hasNext()
+        assert t.hasNext()
+        assert t.hasNext()
+        assert t.hasNext()
+        assert "peter" == t.next()
+        assert not(t.hasNext())
+        assert not(t.hasNext())
+        assert not(t.hasNext())
+        assert not(t.hasNext())
+        assert not(t.hasNext())
+
+        try:
+            t.next()
+            assert False
+        except StopIteration:
+            assert True
+
+    def test_strategies(self, remote_connection):
+        statics.load_statics(globals())
+        g = traversal().withRemote(remote_connection). \
+            withStrategies(TraversalStrategy("SubgraphStrategy",
+                                             {"vertices": __.hasLabel("person"),
+                                              "edges": __.hasLabel("created")},
+                                              "org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy"))
+        assert 4 == g.V().count().next()
+        assert 0 == g.E().count().next()
+        assert 1 == g.V().label().dedup().count().next()
+        assert 4 == g.V().filter(lambda: ("x -> true", "gremlin-groovy")).count().next()
+        assert "person" == g.V().label().dedup().next()
+        #
+        g = traversal().withRemote(remote_connection). \
+            withStrategies(SubgraphStrategy(vertices=__.hasLabel("person"), edges=__.hasLabel("created")))
+        assert 4 == g.V().count().next()
+        assert 0 == g.E().count().next()
+        assert 1 == g.V().label().dedup().count().next()
+        assert "person" == g.V().label().dedup().next()
+        #
+        g = traversal().withRemote(remote_connection). \
+            withStrategies(SubgraphStrategy(edges=__.hasLabel("created")))
+        assert 6 == g.V().count().next()
+        assert 4 == g.E().count().next()
+        assert 1 == g.E().label().dedup().count().next()
+        assert "created" == g.E().label().dedup().next()
+        #
+        g = g.withoutStrategies(SubgraphStrategy). \
+            withComputer(vertices=__.has("name", "marko"), edges=__.limit(0))
+        assert 1 == g.V().count().next()
+        assert 0 == g.E().count().next()
+        assert "person" == g.V().label().next()
+        assert "marko" == g.V().name.next()
+        #
+        g = traversal().withRemote(remote_connection).withComputer()
+        assert 6 == g.V().count().next()
+        assert 6 == g.E().count().next()
+        #
+        g = traversal().withRemote(remote_connection).withStrategies(SeedStrategy(12345))
+        shuffledResult = g.V().values("name").order().by(Order.shuffle).toList()
+        assert shuffledResult == g.V().values("name").order().by(Order.shuffle).toList()
+        assert shuffledResult == g.V().values("name").order().by(Order.shuffle).toList()
+        assert shuffledResult == g.V().values("name").order().by(Order.shuffle).toList()
+        #
+        g = traversal().withRemote(remote_connection). \
+            withStrategies(ReservedKeysVerificationStrategy(throw_exception=True))
+        try:
+            g.addV("person").property("id", "please-don't-use-id").iterate()
+            assert False
+        except GremlinServerError as gse:
+            assert gse.status_code == 500
+        #
+        g = traversal().withRemote(remote_connection).with_("x", True).with_('evaluationTimeout', 10)
+        try:
+            g.inject(1).sideEffect(lambda: ("Thread.sleep(5000)", "gremlin-groovy")).iterate()
+            assert False
+        except GremlinServerError as gse:
+            assert gse.status_code == 598
+
+    def test_clone(self, remote_connection):
+        g = traversal().withRemote(remote_connection)
+        t = g.V().both()
+        assert 12 == len(t.toList())
+        assert 5 == t.clone().limit(5).count().next()
+        assert 10 == t.clone().limit(10).count().next()
+
+    def test_authenticated(self, remote_connection_authenticated):
+        statics.load_statics(globals())
+        g = traversal().withRemote(remote_connection_authenticated)
+
+        assert long(6) == g.V().count().toList()[0]
diff --git a/gremlin-python/src/main/python/tests/driver/test_driver_remote_connection_threaded.py b/gremlin-python/src/main/python/tests/driver/test_driver_remote_connection_threaded.py
new file mode 100644
index 0000000..c3899a4
--- /dev/null
+++ b/gremlin-python/src/main/python/tests/driver/test_driver_remote_connection_threaded.py
@@ -0,0 +1,96 @@
+#
+# 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.
+#
+import concurrent.futures
+import sys
+from threading import Thread
+from six.moves import queue
+
+from gremlin_python.driver.driver_remote_connection import (
+    DriverRemoteConnection)
+from gremlin_python.process.anonymous_traversal import traversal
+
+__author__ = 'David M. Brown (davebshow@gmail.com)'
+
+
+def test_conns_in_threads(remote_connection):
+    q = queue.Queue()
+    child = Thread(target=_executor, args=(q, None))
+    child2 = Thread(target=_executor, args=(q, None))
+    child.start()
+    child2.start()
+    for x in range(2):
+        success = q.get()
+        assert success == 'success!'
+    child.join()
+    child2.join()
+
+
+def test_conn_in_threads(remote_connection):
+    q = queue.Queue()
+    child = Thread(target=_executor, args=(q, remote_connection))
+    child2 = Thread(target=_executor, args=(q, remote_connection))
+    child.start()
+    child2.start()
+    for x in range(2):
+        success = q.get()
+        assert success == 'success!'
+    child.join()
+    child2.join()
+
+
+def _executor(q, conn):
+    close = False
+    if not conn:
+        # This isn't a fixture so close manually
+        close = True
+        conn = DriverRemoteConnection(
+            'ws://localhost:45940/gremlin', 'gmodern', pool_size=4)
+    try:
+        g = traversal().withRemote(conn)
+        future = g.V().promise()
+        t = future.result()
+        assert len(t.toList()) == 6
+    except:
+        q.put(sys.exc_info()[0])
+    else:
+        q.put('success!')
+        # Close conn
+        if close:
+            conn.close()
+
+
+def handle_request():
+    try:
+        remote_connection = DriverRemoteConnection("ws://localhost:45940/gremlin", "g")
+        g = traversal().withRemote(remote_connection)
+        g.V().limit(1).toList()
+        remote_connection.close()
+        return True
+    except RuntimeError:
+        return False
+
+
+def test_multithread(client):
+    try:
+        for i in range(10):
+            with concurrent.futures.ThreadPoolExecutor() as executor:
+                future = executor.submit(handle_request)
+                assert future.result()
+    except RuntimeError:
+        assert False
diff --git a/gremlin-python/src/main/jython/tests/driver/test_serializer.py b/gremlin-python/src/main/python/tests/driver/test_serializer.py
similarity index 100%
rename from gremlin-python/src/main/jython/tests/driver/test_serializer.py
rename to gremlin-python/src/main/python/tests/driver/test_serializer.py
diff --git a/gremlin-python/src/main/jython/tests/process/__init__.py b/gremlin-python/src/main/python/tests/process/__init__.py
similarity index 100%
rename from gremlin-python/src/main/jython/tests/process/__init__.py
rename to gremlin-python/src/main/python/tests/process/__init__.py
diff --git a/gremlin-python/src/main/jython/tests/process/test_dsl.py b/gremlin-python/src/main/python/tests/process/test_dsl.py
similarity index 100%
rename from gremlin-python/src/main/jython/tests/process/test_dsl.py
rename to gremlin-python/src/main/python/tests/process/test_dsl.py
diff --git a/gremlin-python/src/main/jython/tests/process/test_strategies.py b/gremlin-python/src/main/python/tests/process/test_strategies.py
similarity index 100%
rename from gremlin-python/src/main/jython/tests/process/test_strategies.py
rename to gremlin-python/src/main/python/tests/process/test_strategies.py
diff --git a/gremlin-python/src/main/python/tests/process/test_translator.py b/gremlin-python/src/main/python/tests/process/test_translator.py
new file mode 100644
index 0000000..316ba3b
--- /dev/null
+++ b/gremlin-python/src/main/python/tests/process/test_translator.py
@@ -0,0 +1,374 @@
+# 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.

+#

+

+"""

+Unit tests for the Translator Class.

+"""

+__author__ = 'Kelvin R. Lawrence (gfxman)'

+

+from gremlin_python.structure.graph import Graph

+from gremlin_python.process.graph_traversal import __

+from gremlin_python.process.anonymous_traversal import traversal

+from gremlin_python.process.traversal import *

+from gremlin_python.process.strategies import *

+from gremlin_python.process.translator import *

+from datetime import datetime

+

+

+class TestTraversalStrategies(object):

+

+    def test_translations(self):

+        g = traversal().withGraph(Graph())

+

+        tests = list()

+        # 0

+        tests.append([g.V(),

+                     "g.V()"])

+        # 1

+        tests.append([g.V('1', '2', '3', '4'),

+                     "g.V('1','2','3','4')"])

+        # 2

+        tests.append([g.V('3').valueMap(True),

+                     "g.V('3').valueMap(True)"])

+        # 3

+        tests.append([g.V().constant(5),

+                     "g.V().constant(5)"])

+        # 4

+        tests.append([g.V().constant(1.5),

+                     "g.V().constant(1.5)"])

+        # 5

+        tests.append([g.V().constant('Hello'),

+                     "g.V().constant('Hello')"])

+        # 6

+        tests.append([g.V().hasLabel('airport').limit(5),

+                     "g.V().hasLabel('airport').limit(5)"])

+        # 7

+        tests.append([g.V().hasLabel(within('a', 'b', 'c')),

+                     "g.V().hasLabel(within(['a','b','c']))"])

+        # 8

+        tests.append([g.V().hasLabel('airport', 'continent').out().limit(5),

+                     "g.V().hasLabel('airport','continent').out().limit(5)"])

+        # 9

+        tests.append([g.V().hasLabel('airport').out().values('code').limit(5),

+                     "g.V().hasLabel('airport').out().values('code').limit(5)"])

+        # 10

+        tests.append([g.V('3').as_('a').out('route').limit(10).where(eq('a')).by('region'),

+                     "g.V('3').as('a').out('route').limit(10).where(eq('a')).by('region')"])

+        # 11

+        tests.append([g.V('3').repeat(__.out('route').simplePath()).times(2).path().by('code'),

+                     "g.V('3').repeat(__.out('route').simplePath()).times(2).path().by('code')"])

+        # 12

+        tests.append([g.V().hasLabel('airport').out().has('region', 'US-TX').values('code').limit(5),

+                     "g.V().hasLabel('airport').out().has('region','US-TX').values('code').limit(5)"])

+        # 13

+        tests.append([g.V().hasLabel('airport').union(__.values('city'), __.values('region')).limit(5),

+                     "g.V().hasLabel('airport').union(__.values('city'),__.values('region')).limit(5)"])

+        # 14

+        tests.append([g.V('3').as_('a').out('route', 'routes'),

+                     "g.V('3').as('a').out('route','routes')"])

+        # 15

+        tests.append([g.V().where(__.values('runways').is_(5)),

+                    "g.V().where(__.values('runways').is(5))"])

+        # 16

+        tests.append([g.V('3').repeat(__.out().simplePath()).until(__.has('code', 'AGR')).path().by('code').limit(5),

+                     "g.V('3').repeat(__.out().simplePath()).until(__.has('code','AGR')).path().by('code').limit(5)"])

+        # 17

+        tests.append([g.V().hasLabel('airport').order().by(__.id()),

+                     "g.V().hasLabel('airport').order().by(__.id())"])

+        # 18

+        tests.append([g.V().hasLabel('airport').order().by(T.id),

+                     "g.V().hasLabel('airport').order().by(T.id)"])

+        # 19

+        tests.append([g.V().hasLabel('airport').order().by(__.id(),Order.desc),

+                     "g.V().hasLabel('airport').order().by(__.id(),Order.desc)"])

+        # 20

+        tests.append([g.V().hasLabel('airport').order().by('code',Order.desc),

+                     "g.V().hasLabel('airport').order().by('code',Order.desc)"])

+        # 21

+        tests.append([g.V('1', '2', '3').local(__.out().out().dedup().fold()),

+                     "g.V('1','2','3').local(__.out().out().dedup().fold())"])

+        # 22

+        tests.append([g.V('3').out().path().count(Scope.local),

+                     "g.V('3').out().path().count(Scope.local)"])

+        # 23

+        tests.append([g.E().count(),

+                     "g.E().count()"])

+        # 24

+        tests.append([g.V('5').outE('route').inV().path().limit(10),

+                     "g.V('5').outE('route').inV().path().limit(10)"])

+        # 25

+        tests.append([g.V('5').propertyMap().select(Column.keys),

+                     "g.V('5').propertyMap().select(Column.keys)"])

+        # 26

+        tests.append([g.V('5').propertyMap().select(Column.values),

+                     "g.V('5').propertyMap().select(Column.values)"])

+        # 27

+        tests.append([g.V('3').values('runways').math('_ + 1'),

+                     "g.V('3').values('runways').math('_ + 1')"])

+        # 28

+        tests.append([g.V('3').emit().repeat(__.out().simplePath()).times(3).limit(5).path(),

+                     "g.V('3').emit().repeat(__.out().simplePath()).times(3).limit(5).path()"])

+        # 29

+        tests.append([g.V().match(__.as_('a').has('code', 'LHR').as_('b')).select('b').by('code'),

+                     "g.V().match(__.as('a').has('code','LHR').as('b')).select('b').by('code')"])

+        # 30

+        tests.append([g.V().has('test-using-keyword-as-property','repeat'),

+                     "g.V().has('test-using-keyword-as-property','repeat')"])

+        # 31

+        tests.append([g.V('1').addE('test').to(__.V('4')),

+                     "g.V('1').addE('test').to(__.V('4'))"])

+        # 32

+        tests.append([g.V().values('runways').max(),

+                     "g.V().values('runways').max()"])

+        # 33

+        tests.append([g.V().values('runways').min(),

+                     "g.V().values('runways').min()"])

+        # 34

+        tests.append([g.V().values('runways').sum(),

+                     "g.V().values('runways').sum()"])

+        # 35

+        tests.append([g.V().values('runways').mean(),

+                     "g.V().values('runways').mean()"])

+        # 36

+        tests.append([g.withSack(0).V('3', '5').sack(Operator.sum).by('runways').sack(),

+                     "g.withSack(0).V('3','5').sack(Operator.sum).by('runways').sack()"])

+        # 37

+        tests.append([g.V('3').values('runways').store('x').V('4').values('runways').store('x').by(__.constant(1)).V('6').store('x').by(__.constant(1)).select('x').unfold().sum(),

+                     "g.V('3').values('runways').store('x').V('4').values('runways').store('x').by(__.constant(1)).V('6').store('x').by(__.constant(1)).select('x').unfold().sum()"])

+        # 38

+        tests.append([g.inject(3, 4, 5),

+                     "g.inject(3,4,5)"])

+        # 39

+        tests.append([g.inject([3, 4, 5]),

+                     "g.inject([3, 4, 5])"])

+        # 40

+        tests.append([g.inject(3, 4, 5).count(),

+                     "g.inject(3,4,5).count()"])

+        # 41

+        tests.append([g.V().has('runways', gt(5)).count(),

+                     "g.V().has('runways',gt(5)).count()"])

+        # 42

+        tests.append([g.V().has('runways', lte(5.3)).count(),

+                     "g.V().has('runways',lte(5.3)).count()"])

+        # 43

+        tests.append([g.V().has('code', within(123,124)),

+                     "g.V().has('code',within([123,124]))"])

+        # 44

+        tests.append([g.V().has('code', within(123, 'abc')),

+                     "g.V().has('code',within([123,'abc']))"])

+        # 45

+        tests.append([g.V().has('code', within('abc', 123)),

+                     "g.V().has('code',within(['abc',123]))"])

+        # 46

+        tests.append([g.V().has('code', within('abc', 'xyz')),

+                     "g.V().has('code',within(['abc','xyz']))"])

+        # 47

+        tests.append([g.V('1', '2').has('region', P.within('US-TX','US-GA')),

+                     "g.V('1','2').has('region',within(['US-TX','US-GA']))"])

+        # 48

+        tests.append([g.V().and_(__.has('runways', P.gt(5)), __.has('region','US-TX')),

+                     "g.V().and(__.has('runways',gt(5)),__.has('region','US-TX'))"])

+        # 49

+        tests.append([g.V().union(__.has('runways', gt(5)), __.has('region','US-TX')),

+                     "g.V().union(__.has('runways',gt(5)),__.has('region','US-TX'))"])

+        # 50

+        tests.append([g.V('3').choose(__.values('runways').is_(3),__.constant('three'),__.constant('not three')),

+                     "g.V('3').choose(__.values('runways').is(3),__.constant('three'),__.constant('not three'))"])

+        # 51

+        tests.append([g.V('3').choose(__.values('runways')).option(1,__.constant('three')).option(2,__.constant('not three')),

+                     "g.V('3').choose(__.values('runways')).option(1,__.constant('three')).option(2,__.constant('not three'))"])

+        # 52

+        tests.append([g.V('3').choose(__.values('runways')).option(1.5,__.constant('one and a half')).option(2,__.constant('not three')),

+                     "g.V('3').choose(__.values('runways')).option(1.5,__.constant('one and a half')).option(2,__.constant('not three'))"])

+        # 53

+        tests.append([g.V('3').repeat(__.out().simplePath()).until(__.loops().is_(1)).count(),

+                     "g.V('3').repeat(__.out().simplePath()).until(__.loops().is(1)).count()"])

+        # 54

+        tests.append([g.V().hasLabel('airport').limit(20).group().by('region').by('code').order(Scope.local).by(Column.keys),

+                     "g.V().hasLabel('airport').limit(20).group().by('region').by('code').order(Scope.local).by(Column.keys)"])

+        # 55

+        tests.append([g.V('1').as_('a').V('2').as_('a').select(Pop.all_, 'a'),

+                     "g.V('1').as('a').V('2').as('a').select(Pop.all,'a')"])

+        # 56

+        tests.append([g.addV('test').property(Cardinality.set_, 'p1', 10),

+                     "g.addV('test').property(Cardinality.set,'p1',10)"])

+        # 57

+        tests.append([g.addV('test').property(Cardinality.list_, 'p1', 10),

+                     "g.addV('test').property(Cardinality.list,'p1',10)"])

+

+        # 58

+        tests.append([g.addV('test').property(Cardinality.single, 'p1', 10),

+                     "g.addV('test').property(Cardinality.single,'p1',10)"])

+        # 59

+        tests.append([g.V().limit(5).order().by(T.label),

+                     "g.V().limit(5).order().by(T.label)"])

+

+        # 60

+        tests.append([g.V().range(1, 5),

+                     "g.V().range(1,5)"])

+

+        # 61

+        tests.append([g.addV('test').property('p1', 123),

+                     "g.addV('test').property('p1',123)"])

+

+        # 62

+        tests.append([g.addV('test').property('date',datetime(2021, 2, 1, 9, 30)),

+                     "g.addV('test').property('date',new Date(121,2,1,9,30,0))"])

+        # 63

+        tests.append([g.addV('test').property('date',datetime(2021, 2, 1)),

+                     "g.addV('test').property('date',new Date(121,2,1,0,0,0))"])

+        # 64

+        tests.append([g.addE('route').from_(__.V('1')).to(__.V('2')),

+                     "g.addE('route').from(__.V('1')).to(__.V('2'))"])

+        # 65

+        tests.append([g.withSideEffect('a', [1, 2]).V('3').select('a'),

+                     "g.withSideEffect('a',[1, 2]).V('3').select('a')"])

+        # 66

+        tests.append([g.withSideEffect('a', 1).V('3').select('a'),

+                     "g.withSideEffect('a',1).V('3').select('a')"])

+        # 67

+        tests.append([g.withSideEffect('a', 'abc').V('3').select('a'),

+                     "g.withSideEffect('a','abc').V('3').select('a')"])

+        # 68

+        tests.append([g.V().has('airport', 'region', 'US-NM').limit(3).values('elev').fold().index(),

+                     "g.V().has('airport','region','US-NM').limit(3).values('elev').fold().index()"])

+        # 69

+        tests.append([g.V('3').repeat(__.timeLimit(1000).out().simplePath()).until(__.has('code', 'AGR')).path(),

+                     "g.V('3').repeat(__.timeLimit(1000).out().simplePath()).until(__.has('code','AGR')).path()"])

+

+        # 70

+        tests.append([g.V().hasLabel('airport').where(__.values('elev').is_(gt(14000))),

+                     "g.V().hasLabel('airport').where(__.values('elev').is(gt(14000)))"])

+

+        # 71

+        tests.append([g.V().hasLabel('airport').where(__.out().count().is_(gt(250))).values('code'),

+                     "g.V().hasLabel('airport').where(__.out().count().is(gt(250))).values('code')"])

+

+        # 72

+        tests.append([g.V().hasLabel('airport').filter(__.out().count().is_(gt(250))).values('code'),

+                     "g.V().hasLabel('airport').filter(__.out().count().is(gt(250))).values('code')"])

+        # 73

+        tests.append([g.withSack(0).

+                        V('3').

+                        repeat(__.outE('route').sack(Operator.sum).by('dist').inV()).

+                        until(__.has('code', 'AGR').or_().loops().is_(4)).

+                        has('code', 'AGR').

+                        local(__.union(__.path().by('code').by('dist'),__.sack()).fold()).

+                        limit(10),

+                     "g.withSack(0).V('3').repeat(__.outE('route').sack(Operator.sum).by('dist').inV()).until(__.has('code','AGR').or().loops().is(4)).has('code','AGR').local(__.union(__.path().by('code').by('dist'),__.sack()).fold()).limit(10)"])

+

+        # 74

+        tests.append([g.addV().as_('a').addV().as_('b').addE('knows').from_('a').to('b'),

+                     "g.addV().as('a').addV().as('b').addE('knows').from('a').to('b')"])

+

+        # 75

+        tests.append([g.addV('Person').as_('a').addV('Person').as_('b').addE('knows').from_('a').to('b'),

+                     "g.addV('Person').as('a').addV('Person').as('b').addE('knows').from('a').to('b')"])

+        # 76

+        tests.append([g.V('3').project('Out','In').by(__.out().count()).by(__.in_().count()),

+                     "g.V('3').project('Out','In').by(__.out().count()).by(__.in().count())"])

+        # 77

+        tests.append([g.V('44').out().aggregate('a').out().where(within('a')).path(),

+                     "g.V('44').out().aggregate('a').out().where(within(['a'])).path()"])

+        # 78

+        tests.append([g.V().has('date', datetime(2021, 2, 22)),

+                     "g.V().has('date',new Date(121,2,22,0,0,0))"])

+        # 79

+        tests.append([g.V().has('date', within(datetime(2021, 2, 22), datetime(2021, 1, 1))),

+                      "g.V().has('date',within([new Date(121,2,22,0,0,0),new Date(121,1,1,0,0,0)]))"])

+        # 80

+        tests.append([g.V().has('date', between(datetime(2021, 1, 1), datetime(2021, 2, 22))),

+                                "g.V().has('date',between(new Date(121,1,1,0,0,0),new Date(121,2,22,0,0,0)))"])

+        # 81

+        tests.append([g.V().has('date', inside(datetime(2021, 1, 1),datetime(2021, 2, 22))),

+                                "g.V().has('date',inside(new Date(121,1,1,0,0,0),new Date(121,2,22,0,0,0)))"])

+        # 82

+        tests.append([g.V().has('date', P.gt(datetime(2021, 1, 1, 9, 30))),

+                     "g.V().has('date',gt(new Date(121,1,1,9,30,0)))"])

+        # 83

+        tests.append([g.V().has('runways', between(3,5)),

+                     "g.V().has('runways',between(3,5))"])

+        # 84

+        tests.append([g.V().has('runways', inside(3,5)),

+                     "g.V().has('runways',inside(3,5))"])

+        # 85

+        tests.append([g.V('44').outE().elementMap(),

+                     "g.V('44').outE().elementMap()"])

+        # 86

+        tests.append([g.V('44').valueMap().by(__.unfold()),

+                     "g.V('44').valueMap().by(__.unfold())"])

+        # 87

+        tests.append([g.V('44').valueMap().with_(WithOptions.tokens,WithOptions.labels),

+                     "g.V('44').valueMap().with(WithOptions.tokens,WithOptions.labels)"])

+        # 88

+        tests.append([g.V('44').valueMap().with_(WithOptions.tokens),

+                     "g.V('44').valueMap().with(WithOptions.tokens)"])

+        # 89

+        tests.append([g.withStrategies(ReadOnlyStrategy()).addV('test'),

+                      "g.withStrategies(new ReadOnlyStrategy()).addV('test')"])

+        # 90

+        strategy = SubgraphStrategy(vertices=__.has('region', 'US-TX'), edges=__.hasLabel('route'))

+        tests.append([g.withStrategies(strategy).V().count(),

+                    "g.withStrategies(new SubgraphStrategy(vertices:__.has('region','US-TX'),edges:__.hasLabel('route'))).V().count()"])

+        # 91

+        strategy = SubgraphStrategy(vertex_properties=__.hasNot('runways'))

+        tests.append([g.withStrategies(strategy).V().count(),

+                      "g.withStrategies(new SubgraphStrategy(vertexProperties:__.hasNot('runways'))).V().count()"])

+        # 92

+        strategy = SubgraphStrategy(vertices=__.has('region', 'US-TX'),vertex_properties=__.hasNot('runways'))

+        tests.append([g.withStrategies(strategy).V().count(),

+                      "g.withStrategies(new SubgraphStrategy(vertices:__.has('region','US-TX'),vertexProperties:__.hasNot('runways'))).V().count()"])

+        # 93

+        strategy = SubgraphStrategy(vertices=__.has('region', 'US-TX'), edges=__.hasLabel('route'))

+        tests.append([g.withStrategies(ReadOnlyStrategy(),strategy).V().count(),

+                      "g.withStrategies(new ReadOnlyStrategy(),new SubgraphStrategy(vertices:__.has('region','US-TX'),edges:__.hasLabel('route'))).V().count()"])

+        # 94

+        strategy = SubgraphStrategy(vertices=__.has('region', 'US-TX'))

+        tests.append([g.withStrategies(ReadOnlyStrategy(), strategy).V().count(),

+                      "g.withStrategies(new ReadOnlyStrategy(),new SubgraphStrategy(vertices:__.has('region','US-TX'))).V().count()"])

+        # 95

+        tests.append([g.with_('evaluationTimeout', 500).V().count(),

+                      "g.withStrategies(new OptionsStrategy(evaluationTimeout:500)).V().count()"])

+        # 96

+        tests.append([g.withStrategies(OptionsStrategy({'evaluationTimeout': 500})).V().count(),

+                     "g.withStrategies(new OptionsStrategy(evaluationTimeout:500)).V().count()"])

+        # 97

+        tests.append([g.withStrategies(PartitionStrategy(partition_key="partition", write_partition="a", read_partitions=["a"])).addV('test'),

+                     "g.withStrategies(new PartitionStrategy(partitionKey:'partition',writePartition:'a',readPartitions:['a'])).addV('test')"])

+        # 98

+        tests.append([g.withComputer().V().shortestPath().with_(ShortestPath.target, __.has('name','peter')),

+                     "g.withStrategies(new VertexProgramStrategy()).V().shortestPath().with('~tinkerpop.shortestPath.target',__.has('name','peter'))"])

+

+        tlr = Translator().of('g')

+

+        for t in range(len(tests)):

+            a = tlr.translate(tests[t][0].bytecode)

+            assert a == tests[t][1]

+

+    def test_target_language(self):

+        tlr = Translator().of('g')

+        assert tlr.get_target_language() == 'gremlin-groovy'

+

+    def test_constructor(self):

+        tlr = Translator().of('g')

+        g = traversal().withGraph(Graph())

+        assert tlr.translate(g.V().bytecode) == "g.V()"

+

+    def test_source_name(self):

+        tlr = Translator().of('g')

+        assert tlr.get_traversal_source() == 'g'

diff --git a/gremlin-python/src/main/python/tests/process/test_traversal.py b/gremlin-python/src/main/python/tests/process/test_traversal.py
new file mode 100644
index 0000000..f731b84
--- /dev/null
+++ b/gremlin-python/src/main/python/tests/process/test_traversal.py
@@ -0,0 +1,131 @@
+#
+# 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.
+#
+
+__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
+
+from pytest import fail
+
+from gremlin_python.structure.graph import Graph
+from gremlin_python.process.anonymous_traversal import traversal
+from gremlin_python.process.traversal import P
+from gremlin_python.process.traversal import Binding, Bindings
+from gremlin_python.process.graph_traversal import __
+
+
+class TestTraversal(object):
+    def test_bytecode(self):
+        g = traversal().withGraph(Graph())
+        bytecode = g.V().out("created").bytecode
+        assert 0 == len(bytecode.bindings.keys())
+        assert 0 == len(bytecode.source_instructions)
+        assert 2 == len(bytecode.step_instructions)
+        assert "V" == bytecode.step_instructions[0][0]
+        assert "out" == bytecode.step_instructions[1][0]
+        assert "created" == bytecode.step_instructions[1][1]
+        assert 1 == len(bytecode.step_instructions[0])
+        assert 2 == len(bytecode.step_instructions[1])
+        ##
+        bytecode = g.withSack(1).E().groupCount().by("weight").bytecode
+        assert 0 == len(bytecode.bindings.keys())
+        assert 1 == len(bytecode.source_instructions)
+        assert "withSack" == bytecode.source_instructions[0][0]
+        assert 1 == bytecode.source_instructions[0][1]
+        assert 3 == len(bytecode.step_instructions)
+        assert "E" == bytecode.step_instructions[0][0]
+        assert "groupCount" == bytecode.step_instructions[1][0]
+        assert "by" == bytecode.step_instructions[2][0]
+        assert "weight" == bytecode.step_instructions[2][1]
+        assert 1 == len(bytecode.step_instructions[0])
+        assert 1 == len(bytecode.step_instructions[1])
+        assert 2 == len(bytecode.step_instructions[2])
+        ##
+        bytecode = g.V(Bindings.of('a', [1, 2, 3])) \
+            .out(Bindings.of('b', 'created')) \
+            .where(__.in_(Bindings.of('c', 'created'), Bindings.of('d', 'knows')) \
+            .count().is_(Bindings.of('e', P.gt(2)))).bytecode
+        assert 5 == len(bytecode.bindings.keys())
+        assert [1,2,3] == bytecode.bindings['a']
+        assert 'created' == bytecode.bindings['b']
+        assert 'created' == bytecode.bindings['c']
+        assert 'knows' == bytecode.bindings['d']
+        assert P.gt(2) == bytecode.bindings['e']
+        assert Binding('b', 'created') == bytecode.step_instructions[1][1]
+        assert 'binding[b=created]' == str(bytecode.step_instructions[1][1])
+        assert isinstance(hash(bytecode.step_instructions[1][1]), int)
+
+    def test_P(self):
+        # verify that the order of operations is respected
+        assert "and(eq(a),lt(b))" == str(P.eq("a").and_(P.lt("b")))
+        assert "and(or(lt(b),gt(c)),neq(d))" == str(P.lt("b").or_(P.gt("c")).and_(P.neq("d")))
+        assert "and(or(lt(b),gt(c)),or(neq(d),gte(e)))" == str(
+            P.lt("b").or_(P.gt("c")).and_(P.neq("d").or_(P.gte("e"))))
+
+    def test_anonymous_traversal(self):
+        bytecode = __.__(1).bytecode
+        assert 0 == len(bytecode.bindings.keys())
+        assert 0 == len(bytecode.source_instructions)
+        assert 1 == len(bytecode.step_instructions)
+        assert "inject" == bytecode.step_instructions[0][0]
+        assert 1 == bytecode.step_instructions[0][1]
+        ##
+        bytecode = __.start().bytecode
+        assert 0 == len(bytecode.bindings.keys())
+        assert 0 == len(bytecode.source_instructions)
+        assert 0 == len(bytecode.step_instructions)
+
+    def test_clone_traversal(self):
+        g = traversal().withGraph(Graph())
+        original = g.V().out("created")
+        clone = original.clone().out("knows")
+        cloneClone = clone.clone().out("created")
+
+        assert 2 == len(original.bytecode.step_instructions)
+        assert 3 == len(clone.bytecode.step_instructions)
+        assert 4 == len(cloneClone.bytecode.step_instructions)
+
+        original.has("person", "name", "marko")
+        clone.V().out()
+
+        assert 3 == len(original.bytecode.step_instructions)
+        assert 5 == len(clone.bytecode.step_instructions)
+        assert 4 == len(cloneClone.bytecode.step_instructions)
+
+    def test_no_sugar_for_magic_methods(self):
+        g = traversal().withGraph(Graph())
+
+        t = g.V().age
+        assert 2 == len(t.bytecode.step_instructions)
+
+        try:
+            t = g.V().__len__
+            fail("can't do sugar with magic")
+        except AttributeError as err:
+            assert str(err) == 'Python magic methods or keys starting with double underscore cannot be used for Gremlin sugar - prefer values(__len__)'
+
+    def test_enforce_anonymous_child_traversal(self):
+        g = traversal().withGraph(Graph())
+        g.V(0).addE("self").to(__.V(1))
+
+        try:
+            g.V(0).addE("self").to(g.V(1))
+            assert false
+        except TypeError:
+            pass
+
+
diff --git a/gremlin-python/src/main/jython/tests/structure/__init__.py b/gremlin-python/src/main/python/tests/structure/__init__.py
similarity index 100%
rename from gremlin-python/src/main/jython/tests/structure/__init__.py
rename to gremlin-python/src/main/python/tests/structure/__init__.py
diff --git a/gremlin-python/src/main/jython/tests/structure/io/__init__.py b/gremlin-python/src/main/python/tests/structure/io/__init__.py
similarity index 100%
rename from gremlin-python/src/main/jython/tests/structure/io/__init__.py
rename to gremlin-python/src/main/python/tests/structure/io/__init__.py
diff --git a/gremlin-python/src/main/python/tests/structure/io/test_functionalityio.py b/gremlin-python/src/main/python/tests/structure/io/test_functionalityio.py
new file mode 100644
index 0000000..d221b18
--- /dev/null
+++ b/gremlin-python/src/main/python/tests/structure/io/test_functionalityio.py
@@ -0,0 +1,96 @@
+'''
+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.
+'''
+
+import datetime
+import uuid
+
+from gremlin_python.driver.serializer import GraphSONSerializersV2d0
+from gremlin_python.structure.graph import Graph
+from gremlin_python.statics import *
+
+
+def test_timestamp(remote_connection):
+    g = Graph().traversal().withRemote(remote_connection)
+    ts = timestamp(1481750076295 / 1000)
+    resp = g.addV('test_vertex').property('ts', ts)
+    resp = resp.toList()
+    vid = resp[0].id
+    try:
+        ts_prop = g.V(vid).properties('ts').toList()[0]
+        assert isinstance(ts_prop.value, timestamp)
+        assert ts_prop.value == ts
+    finally:
+        g.V(vid).drop().iterate()
+
+
+def test_datetime(remote_connection):
+    g = Graph().traversal().withRemote(remote_connection)
+    dt = datetime.datetime.utcfromtimestamp(1481750076295 / 1000)
+    resp = g.addV('test_vertex').property('dt', dt).toList()
+    vid = resp[0].id
+    try:
+        dt_prop = g.V(vid).properties('dt').toList()[0]
+        assert isinstance(dt_prop.value, datetime.datetime)
+        assert dt_prop.value == dt
+    finally:
+        g.V(vid).drop().iterate()
+
+
+def test_uuid(remote_connection):
+    g = Graph().traversal().withRemote(remote_connection)
+    uid = uuid.UUID("41d2e28a-20a4-4ab0-b379-d810dede3786")
+    resp = g.addV('test_vertex').property('uuid', uid).toList()
+    vid = resp[0].id
+    try:
+        uid_prop = g.V(vid).properties('uuid').toList()[0]
+        assert isinstance(uid_prop.value, uuid.UUID)
+        assert uid_prop.value == uid
+    finally:
+        g.V(vid).drop().iterate()
+
+
+def test_odd_bits(remote_connection):
+    if not isinstance(remote_connection._client._message_serializer, GraphSONSerializersV2d0):
+        g = Graph().traversal().withRemote(remote_connection)
+        char_lower = str.__new__(SingleChar, chr(78))
+        resp = g.addV('test_vertex').property('char_lower', char_lower).toList()
+        vid = resp[0].id
+        try:
+            v = g.V(vid).values('char_lower').toList()[0]
+            assert v == char_lower
+        finally:
+            g.V(vid).drop().iterate()
+
+        char_upper = str.__new__(SingleChar, chr(57344))
+        resp = g.addV('test_vertex').property('char_upper', char_upper).toList()
+        vid = resp[0].id
+        try:
+            v = g.V(vid).values('char_upper').toList()[0]
+            assert v == char_upper
+        finally:
+            g.V(vid).drop().iterate()
+                
+        dur = datetime.timedelta(seconds=1000, microseconds=1000)
+        resp = g.addV('test_vertex').property('dur', dur).toList()
+        vid = resp[0].id
+        try:
+            v = g.V(vid).values('dur').toList()[0]
+            assert v == dur
+        finally:
+            g.V(vid).drop().iterate()
diff --git a/gremlin-python/src/main/python/tests/structure/io/test_graphbinaryV1.py b/gremlin-python/src/main/python/tests/structure/io/test_graphbinaryV1.py
new file mode 100644
index 0000000..2f2b211
--- /dev/null
+++ b/gremlin-python/src/main/python/tests/structure/io/test_graphbinaryV1.py
@@ -0,0 +1,213 @@
+"""
+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.
+"""
+
+import datetime
+import uuid
+import math
+
+from gremlin_python.statics import timestamp, long, SingleByte, SingleChar, ByteBufferType
+from gremlin_python.structure.graph import Vertex, Edge, Property, VertexProperty, Path
+from gremlin_python.structure.io.graphbinaryV1 import GraphBinaryWriter, GraphBinaryReader
+from gremlin_python.process.traversal import Barrier, Binding, Bytecode
+
+
+class TestGraphBinaryReader(object):
+    graphbinary_reader = GraphBinaryReader()
+
+
+class TestGraphSONWriter(object):
+    graphbinary_writer = GraphBinaryWriter()
+    graphbinary_reader = GraphBinaryReader()
+
+    def test_null(self):
+        c = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(None))
+        assert c is None
+
+    def test_int(self):
+        x = 100
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert x == output
+
+    def test_long(self):
+        x = long(100)
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert x == output
+
+    def test_float(self):
+        x = float(100.001)
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert x == output
+
+        x = float('nan')
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert math.isnan(output)
+
+        x = float('-inf')
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert math.isinf(output) and output < 0
+
+        x = float('inf')
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert math.isinf(output) and output > 0
+
+    def test_double(self):
+        x = 100.001
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert x == output
+
+    def test_date(self):
+        x = datetime.datetime(2016, 12, 14, 16, 14, 36, 295000)
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert x == output
+
+    def test_timestamp(self):
+        x = timestamp(1481750076295 / 1000)
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert x == output
+
+    def test_string(self):
+        x = "serialize this!"
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert x == output
+
+    def test_homogeneous_list(self):
+        x = ["serialize this!", "serialize that!", "serialize that!","stop telling me what to serialize"]
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert x == output
+
+    def test_heterogeneous_list(self):
+        x = ["serialize this!", 0, "serialize that!", "serialize that!", 1, "stop telling me what to serialize", 2]
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert x == output
+
+    def test_heterogeneous_list_with_none(self):
+        x = ["serialize this!", 0, "serialize that!", "serialize that!", 1, "stop telling me what to serialize", 2, None]
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert x == output
+
+    def test_homogeneous_set(self):
+        x = {"serialize this!", "serialize that!", "stop telling me what to serialize"}
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert x == output
+
+    def test_heterogeneous_set(self):
+        x = {"serialize this!", 0, "serialize that!", 1, "stop telling me what to serialize", 2}
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert x == output
+
+    def test_dict(self):
+        x = {"yo": "what?",
+             "go": "no!",
+             "number": 123,
+             321: "crazy with the number for a key",
+             987: ["go", "deep", {"here": "!"}]}
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert x == output
+
+        x = {"marko": [666], "noone": ["blah"]}
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert x == output
+
+        x = {"ripple": [], "peter": ["created"], "noone": ["blah"], "vadas": [],
+             "josh": ["created", "created"], "lop": [], "marko": [666, "created", "knows", "knows"]}
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert x == output
+
+    def test_uuid(self):
+        x = uuid.UUID("41d2e28a-20a4-4ab0-b379-d810dede3786")
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert x == output
+
+    def test_edge(self):
+        x = Edge(123, Vertex(1, 'person'), "developed", Vertex(10, "software"))
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert x == output
+        assert x.inV == output.inV
+        assert x.outV == output.outV
+
+    def test_path(self):
+        x = Path(["x", "y", "z"], [1, 2, 3])
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert x == output
+
+    def test_property(self):
+        x = Property("name", "stephen", None)
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert x == output
+
+    def test_vertex(self):
+        x = Vertex(123, "person")
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert x == output
+
+    def test_vertexproperty(self):
+        x = VertexProperty(123, "name", "stephen", None)
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert x == output
+        
+    def test_barrier(self):
+        x = Barrier.normSack
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert x == output
+
+    def test_binding(self):
+        x = Binding("name", "marko")
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert x == output
+
+    def test_bytecode(self):
+        x = Bytecode()
+        x.source_instructions.append(["withStrategies", "SubgraphStrategy"])
+        x.step_instructions.append(["V", 1, 2, 3])
+        x.step_instructions.append(["out"])
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert x == output
+
+    def test_byte(self):
+        x = int.__new__(SingleByte, 1)
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert x == output
+
+    def test_bytebuffer(self):
+        x = ByteBufferType("c29tZSBieXRlcyBmb3IgeW91", "utf8")
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert x == output
+
+    def test_boolean(self):
+        x = True
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert x == output
+
+        x = False
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert x == output
+
+    def test_char(self):
+        x = str.__new__(SingleChar, chr(76))
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert x == output
+
+        x = str.__new__(SingleChar, chr(57344))
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert x == output
+
+    def test_duration(self):
+        x = datetime.timedelta(seconds=1000, microseconds=1000)
+        output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x))
+        assert x == output
diff --git a/gremlin-python/src/main/python/tests/structure/io/test_graphsonV2d0.py b/gremlin-python/src/main/python/tests/structure/io/test_graphsonV2d0.py
new file mode 100644
index 0000000..8cc4fb5
--- /dev/null
+++ b/gremlin-python/src/main/python/tests/structure/io/test_graphsonV2d0.py
@@ -0,0 +1,518 @@
+#
+# 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.
+#
+
+__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
+
+import datetime
+import calendar
+import json
+import uuid
+import math
+from decimal import *
+
+from mock import Mock
+
+from gremlin_python.statics import *
+from gremlin_python.structure.graph import Vertex, Edge, Property, VertexProperty, Graph, Path
+from gremlin_python.structure.io.graphsonV2d0 import GraphSONWriter, GraphSONReader, GraphSONUtil
+import gremlin_python.structure.io.graphsonV2d0
+from gremlin_python.process.traversal import P
+from gremlin_python.process.strategies import SubgraphStrategy
+from gremlin_python.process.graph_traversal import __
+
+
+class TestGraphSONReader(object):
+    graphson_reader = GraphSONReader()
+
+    def test_number_input(self):
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "gx:Byte",
+            "@value": 1
+        }))
+        assert isinstance(x, SingleByte)
+        assert 1 == x
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "g:Int32",
+            "@value": 31
+        }))
+        assert isinstance(x, int)
+        assert 31 == x
+        ##
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "g:Int64",
+            "@value": 31
+        }))
+        assert isinstance(x, long)
+        assert long(31) == x
+        ##
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "g:Float",
+            "@value": 31.3
+        }))
+        assert isinstance(x, float)
+        assert 31.3 == x
+        ##
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "g:Double",
+            "@value": 31.2
+        }))
+        assert isinstance(x, float)
+        assert 31.2 == x
+        ##
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "g:Double",
+            "@value": "NaN"
+        }))
+        assert isinstance(x, float)
+        assert math.isnan(x)
+        ##
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "g:Double",
+            "@value": "Infinity"
+        }))
+        assert isinstance(x, float)
+        assert math.isinf(x) and x > 0
+        ##
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "g:Double",
+            "@value": "-Infinity"
+        }))
+        assert isinstance(x, float)
+        assert math.isinf(x) and x < 0
+        ##
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "gx:BigDecimal",
+            "@value": 31.2
+        }))
+        assert isinstance(x, Decimal)
+        assert Decimal(31.2) == x
+        ##
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "gx:BigDecimal",
+            "@value": 123456789987654321123456789987654321
+        }))
+        assert isinstance(x, Decimal)
+        assert Decimal('123456789987654321123456789987654321') == x
+        ##
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "gx:BigDecimal",
+            "@value": "NaN"
+        }))
+        assert isinstance(x, Decimal)
+        assert math.isnan(x)
+        ##
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "gx:BigDecimal",
+            "@value": "Infinity"
+        }))
+        assert isinstance(x, Decimal)
+        assert math.isinf(x) and x > 0
+        ##
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "gx:BigDecimal",
+            "@value": "-Infinity"
+        }))
+        assert isinstance(x, Decimal)
+        assert math.isinf(x) and x < 0
+        ##
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "gx:BigInteger",
+            "@value": 31
+        }))
+        assert isinstance(x, long)
+        assert 31 == x
+        ##
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "gx:BigInteger",
+            "@value": 123456789987654321123456789987654321
+        }))
+        assert isinstance(x, long)
+        assert 123456789987654321123456789987654321 == x
+
+    def test_graph(self):
+        vertex = self.graphson_reader.readObject("""
+        {"@type":"g:Vertex", "@value":{"id":{"@type":"g:Int32","@value":1},"label":"person","outE":{"created":[{"id":{"@type":"g:Int32","@value":9},"inV":{"@type":"g:Int32","@value":3},"properties":{"weight":{"@type":"g:Double","@value":0.4}}}],"knows":[{"id":{"@type":"g:Int32","@value":7},"inV":{"@type":"g:Int32","@value":2},"properties":{"weight":{"@type":"g:Double","@value":0.5}}},{"id":{"@type":"g:Int32","@value":8},"inV":{"@type":"g:Int32","@value":4},"properties":{"weight":{"@type":"g:Double","@value":1.0}}}]},"properties":{"name":[{"id":{"@type":"g:Int64","@value":0},"value":"marko"}],"age":[{"id":{"@type":"g:Int64","@value":1},"value":{"@type":"g:Int32","@value":29}}]}}}""")
+        assert isinstance(vertex, Vertex)
+        assert "person" == vertex.label
+        assert 1 == vertex.id
+        assert isinstance(vertex.id, int)
+        assert vertex == Vertex(1)
+        ##
+        vertex = self.graphson_reader.readObject("""
+        {"@type":"g:Vertex", "@value":{"id":{"@type":"g:Float","@value":45.23}}}""")
+        assert isinstance(vertex, Vertex)
+        assert 45.23 == vertex.id
+        assert isinstance(vertex.id, FloatType)
+        assert "vertex" == vertex.label
+        assert vertex == Vertex(45.23)
+        ##
+        vertex_property = self.graphson_reader.readObject("""
+        {"@type":"g:VertexProperty", "@value":{"id":"anId","label":"aKey","value":true,"vertex":{"@type":"g:Int32","@value":9}}}""")
+        assert isinstance(vertex_property, VertexProperty)
+        assert "anId" == vertex_property.id
+        assert "aKey" == vertex_property.label
+        assert vertex_property.value
+        assert vertex_property.vertex == Vertex(9)
+        ##
+        vertex_property = self.graphson_reader.readObject("""
+        {"@type":"g:VertexProperty", "@value":{"id":{"@type":"g:Int32","@value":1},"label":"name","value":"marko"}}""")
+        assert isinstance(vertex_property, VertexProperty)
+        assert 1 == vertex_property.id
+        assert "name" == vertex_property.label
+        assert "marko" == vertex_property.value
+        assert vertex_property.vertex is None
+        ##
+        edge = self.graphson_reader.readObject("""
+        {"@type":"g:Edge", "@value":{"id":{"@type":"g:Int64","@value":17},"label":"knows","inV":"x","outV":"y","inVLabel":"xLab","properties":{"aKey":"aValue","bKey":true}}}""")
+        # print edge
+        assert isinstance(edge, Edge)
+        assert 17 == edge.id
+        assert "knows" == edge.label
+        assert edge.inV == Vertex("x", "xLabel")
+        assert edge.outV == Vertex("y", "vertex")
+        ##
+        property = self.graphson_reader.readObject("""
+        {"@type":"g:Property", "@value":{"key":"aKey","value":{"@type":"g:Int64","@value":17},"element":{"@type":"g:Edge","@value":{"id":{"@type":"g:Int64","@value":122},"label":"knows","inV":"x","outV":"y","inVLabel":"xLab"}}}}""")
+        # print property
+        assert isinstance(property, Property)
+        assert "aKey" == property.key
+        assert 17 == property.value
+        assert Edge(122, Vertex("x"), "knows", Vertex("y")) == property.element
+
+    def test_path(self):
+        path = self.graphson_reader.readObject(
+            """{"@type":"g:Path","@value":{"labels":[["a"],["b","c"],[]],"objects":[{"@type":"g:Vertex","@value":{"id":{"@type":"g:Int32","@value":1},"label":"person","properties":{"name":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":0},"value":"marko","label":"name"}}],"age":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":1},"value":{"@type":"g:Int32","@value":29},"label":"age"}}]}}},{"@type":"g:Vertex","@value":{"id":{"@type":"g:Int32","@value":3},"label":"software","properties":{"name":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":4},"value":"lop","label":"name"}}],"lang":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":5},"value":"java","label":"lang"}}]}}},"lop"]}}"""
+        )
+        assert isinstance(path, Path)
+        assert "path[v[1], v[3], lop]" == str(path)
+        assert Vertex(1) == path[0]
+        assert Vertex(1) == path["a"]
+        assert "lop" == path[2]
+        assert 3 == len(path)
+
+    def test_custom_mapping(self):
+
+        # extended mapping
+        class X(object):
+            pass
+
+        type_string = "test:Xtype"
+        override_string = "g:Int64"
+        serdes = Mock()
+
+        reader = GraphSONReader(deserializer_map={type_string: serdes})
+        assert type_string in reader.deserializers
+
+        # base dicts are not modified
+        assert type_string not in gremlin_python.structure.io.graphsonV2d0._deserializers
+
+        x = X()
+        o = reader.toObject({GraphSONUtil.TYPE_KEY: type_string, GraphSONUtil.VALUE_KEY: x})
+        serdes.objectify.assert_called_once_with(x, reader)
+        assert o is serdes.objectify()
+
+        # overridden mapping
+        type_string = "g:Int64"
+        serdes = Mock()
+        reader = GraphSONReader(deserializer_map={type_string: serdes, override_string: serdes})
+        assert gremlin_python.structure.io.graphsonV2d0._deserializers[type_string] is not reader.deserializers[type_string]
+
+        value = 3
+        o = reader.toObject({GraphSONUtil.TYPE_KEY: type_string, GraphSONUtil.VALUE_KEY: value})
+        serdes.objectify.assert_called_once_with(value, reader)
+        assert o is serdes.objectify()
+
+    def test_datetime(self):
+        expected = datetime.datetime(2016, 12, 14, 16, 14, 36, 295000)
+        pts = calendar.timegm(expected.utctimetuple()) + expected.microsecond / 1e6
+        ts = int(round(pts * 1000))
+        dt = self.graphson_reader.readObject(json.dumps({"@type": "g:Date", "@value": ts}))
+        assert isinstance(dt, datetime.datetime)
+        # TINKERPOP-1848
+        assert dt == expected
+
+    def test_timestamp(self):
+        dt = self.graphson_reader.readObject(json.dumps({"@type": "g:Timestamp", "@value": 1481750076295}))
+        assert isinstance(dt, timestamp)
+        assert float(dt) == 1481750076.295
+
+    def test_duration(self):
+        d = self.graphson_reader.readObject(json.dumps({"@type": "gx:Duration", "@value": "PT120H"}))
+        assert isinstance(d, datetime.timedelta)
+        assert d == datetime.timedelta(hours=120)
+
+    def test_uuid(self):
+        prop = self.graphson_reader.readObject(
+            json.dumps({'@type': 'g:UUID', '@value': "41d2e28a-20a4-4ab0-b379-d810dede3786"}))
+        assert isinstance(prop, uuid.UUID)
+        assert str(prop) == '41d2e28a-20a4-4ab0-b379-d810dede3786'
+
+    def test_metrics(self):
+        prop = self.graphson_reader.readObject(
+            json.dumps([{'@type': 'g:TraversalMetrics', '@value': {'dur': 1.468594, 'metrics': [
+                {'@type': 'g:Metrics', '@value': {'dur': 1.380957, 'counts': {}, 'name': 'GraphStep(__.V())', 'annotations': {'percentDur': 94.03259171697556}, 'id': '4.0.0()'}},
+                {'@type': 'g:Metrics', '@value': {'dur': 0.087637, 'counts': {}, 'name': 'ReferenceElementStep', 'annotations': {'percentDur': 5.967408283024444}, 'id': '3.0.0()'}}
+            ]}}]))
+        assert isinstance(prop, list)
+        assert prop == [{'dur': 1.468594, 'metrics': [
+                {'dur': 1.380957, 'counts': {}, 'name': 'GraphStep(__.V())', 'annotations': {'percentDur': 94.03259171697556}, 'id': '4.0.0()'},
+                {'dur': 0.087637, 'counts': {}, 'name': 'ReferenceElementStep', 'annotations': {'percentDur': 5.967408283024444}, 'id': '3.0.0()'}
+                ]}]
+
+    def test_bytebuffer(self):
+        bb = self.graphson_reader.readObject(
+            json.dumps({"@type": "gx:ByteBuffer", "@value": "c29tZSBieXRlcyBmb3IgeW91"}))
+        assert isinstance(bb, ByteBufferType)
+        assert ByteBufferType("c29tZSBieXRlcyBmb3IgeW91", "utf8") == bb
+
+    def test_char(self):
+        c = self.graphson_reader.readObject(json.dumps({"@type": "gx:Char", "@value": "L"}))
+        assert isinstance(c, SingleChar)
+        assert chr(76) == c
+
+    def test_null(self):
+        c = self.graphson_reader.readObject(json.dumps(None))
+        assert c is None
+
+
+class TestGraphSONWriter(object):
+    graphson_writer = GraphSONWriter()
+    graphson_reader = GraphSONReader()
+
+    def test_numbers(self):
+        assert {"@type": "gx:Byte", "@value": 1} == json.loads(self.graphson_writer.writeObject(int.__new__(SingleByte, 1)))
+        assert {"@type": "g:Int64", "@value": 2} == json.loads(self.graphson_writer.writeObject(long(2)))
+        assert {"@type": "g:Int64", "@value": 851401972585122} == json.loads(self.graphson_writer.writeObject(long(851401972585122)))
+        assert {"@type": "g:Int64", "@value": -2} == json.loads(self.graphson_writer.writeObject(long(-2)))
+        assert {"@type": "g:Int64", "@value": -851401972585122} == json.loads(self.graphson_writer.writeObject(long(-851401972585122)))
+        assert {"@type": "g:Int32", "@value": 1} == json.loads(self.graphson_writer.writeObject(1))
+        assert {"@type": "g:Int32", "@value": -1} == json.loads(self.graphson_writer.writeObject(-1))
+        assert {"@type": "g:Int64", "@value": 851401972585122} == json.loads(self.graphson_writer.writeObject(851401972585122))
+        assert {"@type": "g:Double", "@value": 3.2} == json.loads(self.graphson_writer.writeObject(3.2))
+        assert {"@type": "g:Double", "@value": "NaN"} == json.loads(self.graphson_writer.writeObject(float('nan')))
+        assert {"@type": "g:Double", "@value": "Infinity"} == json.loads(self.graphson_writer.writeObject(float('inf')))
+        assert {"@type": "g:Double", "@value": "-Infinity"} == json.loads(self.graphson_writer.writeObject(float('-inf')))
+        assert {"@type": "gx:BigDecimal", "@value": "123456789987654321123456789987654321"} == json.loads(self.graphson_writer.writeObject(Decimal('123456789987654321123456789987654321')))
+        assert {"@type": "gx:BigDecimal", "@value": "NaN"} == json.loads(self.graphson_writer.writeObject(Decimal('nan')))
+        assert {"@type": "gx:BigDecimal", "@value": "Infinity"} == json.loads(self.graphson_writer.writeObject(Decimal('inf')))
+        assert {"@type": "gx:BigDecimal", "@value": "-Infinity"} == json.loads(self.graphson_writer.writeObject(Decimal('-inf')))
+        assert {"@type": "gx:BigInteger", "@value": "123456789987654321123456789987654321"} == json.loads(self.graphson_writer.writeObject(long(123456789987654321123456789987654321)))
+        assert {"@type": "gx:BigInteger", "@value": "123456789987654321123456789987654321"} == json.loads(self.graphson_writer.writeObject(123456789987654321123456789987654321))
+        assert """true""" == self.graphson_writer.writeObject(True)
+
+    def test_P(self):
+        result = {'@type': 'g:P',
+                  '@value': {
+                      'predicate': 'and',
+                      'value': [{
+                          '@type': 'g:P',
+                          '@value': {
+                              'predicate': 'or',
+                              'value': [{
+                                  '@type': 'g:P',
+                                  '@value': {'predicate': 'lt', 'value': 'b'}
+                              },
+                                  {'@type': 'g:P', '@value': {'predicate': 'gt', 'value': 'c'}}
+                              ]
+                          }
+                      },
+                          {'@type': 'g:P', '@value': {'predicate': 'neq', 'value': 'd'}}]}}
+
+        assert result == json.loads(
+            self.graphson_writer.writeObject(P.lt("b").or_(P.gt("c")).and_(P.neq("d"))))
+
+        result = {'@type': 'g:P', '@value': {'predicate':'within','value': [{"@type": "g:Int32", "@value": 1},{"@type": "g:Int32", "@value": 2}]}}
+        assert result == json.loads(self.graphson_writer.writeObject(P.within([1, 2])))
+        assert result == json.loads(self.graphson_writer.writeObject(P.within(1, 2)))
+
+        result = {'@type': 'g:P', '@value': {'predicate':'within','value': [{"@type": "g:Int32", "@value": 1}]}}
+        assert result == json.loads(self.graphson_writer.writeObject(P.within([1])))
+        assert result == json.loads(self.graphson_writer.writeObject(P.within(1)))
+
+    def test_strategies(self):
+        # we have a proxy model for now given that we don't want to have to have g:XXX all registered on the Gremlin traversal machine (yet)
+        assert {"@type": "g:SubgraphStrategy", "@value": {}} == json.loads(
+            self.graphson_writer.writeObject(SubgraphStrategy))
+        assert {"@type": "g:SubgraphStrategy", "@value": {
+            "vertices": {"@type": "g:Bytecode", "@value": {"step": [["has", "name", "marko"]]}}}} == json.loads(
+            self.graphson_writer.writeObject(SubgraphStrategy(vertices=__.has("name", "marko"))))
+
+    def test_graph(self):
+        # TODO: this assert is not compatible with python 3 and now that we test with both 2 and 3 it fails
+        assert {"@type": "g:Vertex", "@value": {"id": {"@type": "g:Int64", "@value": 12}, "label": "person"}} == json.loads(self.graphson_writer.writeObject(Vertex(long(12), "person")))
+
+        assert {"@type": "g:Edge", "@value": {"id": {"@type": "g:Int32", "@value": 7},
+                                              "outV": {"@type": "g:Int32", "@value": 0},
+                                              "outVLabel": "person",
+                                              "label": "knows",
+                                              "inV": {"@type": "g:Int32", "@value": 1},
+                                              "inVLabel": "dog"}} == json.loads(
+            self.graphson_writer.writeObject(Edge(7, Vertex(0, "person"), "knows", Vertex(1, "dog"))))
+        assert {"@type": "g:VertexProperty", "@value": {"id": "blah", "label": "keyA", "value": True,
+                                                        "vertex": "stephen"}} == json.loads(
+            self.graphson_writer.writeObject(VertexProperty("blah", "keyA", True, Vertex("stephen"))))
+
+        assert {"@type": "g:Property",
+                "@value": {"key": "name", "value": "marko", "element": {"@type": "g:VertexProperty",
+                                                                        "@value": {
+                                                                            "vertex": "vertexId",
+                                                                            "id": {"@type": "g:Int32", "@value": 1234},
+                                                                            "label": "aKey"}}}} == json.loads(
+            self.graphson_writer.writeObject(
+                Property("name", "marko", VertexProperty(1234, "aKey", 21345, Vertex("vertexId")))))
+
+        vertex = self.graphson_reader.readObject(self.graphson_writer.writeObject(Vertex(1, "person")))
+        assert 1 == vertex.id
+        assert "person" == vertex.label
+
+        edge = self.graphson_reader.readObject(
+            self.graphson_writer.writeObject(Edge(3, Vertex(1, "person"), "knows", Vertex(2, "dog"))))
+        assert "knows" == edge.label
+        assert 3 == edge.id
+        assert 1 == edge.outV.id
+        assert 2 == edge.inV.id
+
+        vertex_property = self.graphson_reader.readObject(
+            self.graphson_writer.writeObject(VertexProperty(1, "age", 32, Vertex(1))))
+        assert 1 == vertex_property.id
+        assert "age" == vertex_property.key
+        assert 32 == vertex_property.value
+
+        property = self.graphson_reader.readObject(self.graphson_writer.writeObject(Property("age", 32.2, Edge(1,Vertex(2),"knows",Vertex(3)))))
+        assert "age" == property.key
+        assert 32.2 == property.value
+
+    def test_custom_mapping(self):
+        # extended mapping
+        class X(object):
+            pass
+
+        serdes = Mock()
+        writer = GraphSONWriter(serializer_map={X: serdes})
+        assert X in writer.serializers
+
+        # base dicts are not modified
+        assert X not in gremlin_python.structure.io.graphsonV2d0._serializers
+
+        obj = X()
+        d = writer.toDict(obj)
+        serdes.dictify.assert_called_once_with(obj, writer)
+        assert d is serdes.dictify()
+
+        # overridden mapping
+        serdes = Mock()
+        writer = GraphSONWriter(serializer_map={int: serdes})
+        assert gremlin_python.structure.io.graphsonV2d0._serializers[int] is not writer.serializers[int]
+
+        value = 3
+        d = writer.toDict(value)
+        serdes.dictify.assert_called_once_with(value, writer)
+        assert d is serdes.dictify()
+
+    def test_write_long(self):
+        mapping = self.graphson_writer.toDict(1)
+        assert mapping['@type'] == 'g:Int32'
+        assert mapping['@value'] == 1
+
+        mapping = self.graphson_writer.toDict(long(1))
+        assert mapping['@type'] == 'g:Int64'
+        assert mapping['@value'] == 1
+
+    def test_datetime(self):
+        expected = json.dumps({"@type": "g:Date", "@value": 1481750076295}, separators=(',', ':'))
+        dt = datetime.datetime.utcfromtimestamp(1481750076295 / 1000.0)
+        output = self.graphson_writer.writeObject(dt)
+        assert expected == output
+
+    def test_timestamp(self):
+        expected = json.dumps({"@type": "g:Timestamp", "@value": 1481750076295}, separators=(',', ':'))
+        ts = timestamp(1481750076295 / 1000.0)
+        output = self.graphson_writer.writeObject(ts)
+        assert expected == output
+
+    def test_duration(self):
+        expected = json.dumps({"@type": "gx:Duration", "@value": "P5D"}, separators=(',', ':'))
+        d = datetime.timedelta(hours=120)
+        output = self.graphson_writer.writeObject(d)
+        assert expected == output
+
+    def test_uuid(self):
+        expected = json.dumps({'@type': 'g:UUID', '@value': "41d2e28a-20a4-4ab0-b379-d810dede3786"}, separators=(',', ':'))
+        prop = uuid.UUID("41d2e28a-20a4-4ab0-b379-d810dede3786")
+        output = self.graphson_writer.writeObject(prop)
+        assert expected == output
+
+    def test_bytebuffer(self):
+        expected = json.dumps({'@type': 'gx:ByteBuffer', '@value': 'c29tZSBieXRlcyBmb3IgeW91'}, separators=(',', ':'))
+        bb = ByteBufferType("c29tZSBieXRlcyBmb3IgeW91", "utf8")
+        output = self.graphson_writer.writeObject(bb)
+        assert expected == output
+
+    def test_char(self):
+        expected = json.dumps({'@type': 'gx:Char', '@value': 'L'}, separators=(',', ':'))
+        c = str.__new__(SingleChar, chr(76))
+        output = self.graphson_writer.writeObject(c)
+        assert expected == output
+
+
+class TestFunctionalGraphSONIO(object):
+    """Functional IO tests"""
+
+    def test_timestamp(self, remote_connection_graphsonV2):
+        g = Graph().traversal().withRemote(remote_connection_graphsonV2)
+        ts = timestamp(1481750076295 / 1000)
+        resp = g.addV('test_vertex').property('ts', ts)
+        resp = resp.toList()
+        vid = resp[0].id
+        try:
+            ts_prop = g.V(vid).properties('ts').toList()[0]
+            assert isinstance(ts_prop.value, timestamp)
+            assert ts_prop.value == ts
+        except OSError:
+            assert False, "Error making request"
+        finally:
+            g.V(vid).drop().iterate()
+
+    def test_datetime(self, remote_connection_graphsonV2):
+        g = Graph().traversal().withRemote(remote_connection_graphsonV2)
+        dt = datetime.datetime.utcfromtimestamp(1481750076295 / 1000)
+        resp = g.addV('test_vertex').property('dt', dt).toList()
+        vid = resp[0].id
+        try:
+            dt_prop = g.V(vid).properties('dt').toList()[0]
+            assert isinstance(dt_prop.value, datetime.datetime)
+            assert dt_prop.value == dt
+        except OSError:
+            assert False, "Error making request"
+        finally:
+            g.V(vid).drop().iterate()
+
+    def test_uuid(self, remote_connection_graphsonV2):
+        g = Graph().traversal().withRemote(remote_connection_graphsonV2)
+        uid = uuid.UUID("41d2e28a-20a4-4ab0-b379-d810dede3786")
+        resp = g.addV('test_vertex').property('uuid', uid).toList()
+        vid = resp[0].id
+        try:
+            uid_prop = g.V(vid).properties('uuid').toList()[0]
+            assert isinstance(uid_prop.value, uuid.UUID)
+            assert uid_prop.value == uid
+        except OSError:
+            assert False, "Error making request"
+        finally:
+            g.V(vid).drop().iterate()
diff --git a/gremlin-python/src/main/python/tests/structure/io/test_graphsonV3d0.py b/gremlin-python/src/main/python/tests/structure/io/test_graphsonV3d0.py
new file mode 100644
index 0000000..83aa55f
--- /dev/null
+++ b/gremlin-python/src/main/python/tests/structure/io/test_graphsonV3d0.py
@@ -0,0 +1,536 @@
+#
+# 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.
+#
+
+__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
+
+import datetime
+import calendar
+import json
+import uuid
+import math
+from decimal import *
+
+from mock import Mock
+
+from gremlin_python.statics import *
+from gremlin_python.structure.graph import Vertex, Edge, Property, VertexProperty, Graph, Path
+from gremlin_python.structure.io.graphsonV3d0 import GraphSONWriter, GraphSONReader, GraphSONUtil
+import gremlin_python.structure.io.graphsonV3d0
+from gremlin_python.process.traversal import P
+from gremlin_python.process.strategies import SubgraphStrategy
+from gremlin_python.process.graph_traversal import __
+
+
+class TestGraphSONReader(object):
+    graphson_reader = GraphSONReader()
+
+    def test_collections(self):
+        x = self.graphson_reader.readObject(
+            json.dumps({"@type": "g:List", "@value": [{"@type": "g:Int32", "@value": 1},
+                                                      {"@type": "g:Int32", "@value": 2},
+                                                      "3"]}))
+        assert isinstance(x, list)
+        assert x[0] == 1
+        assert x[1] == 2
+        assert x[2] == "3"
+        ##
+
+        x = self.graphson_reader.readObject(
+            json.dumps({"@type": "g:Set", "@value": [{"@type": "g:Int32", "@value": 1},
+                                                     {"@type": "g:Int32", "@value": 2},
+                                                     "3"]}))
+        # return a set as normal
+        assert isinstance(x, set)
+        assert x == set([1, 2, "3"])
+
+        x = self.graphson_reader.readObject(
+            json.dumps({"@type": "g:Set", "@value": [{"@type": "g:Int32", "@value": 1},
+                                                    {"@type": "g:Int32", "@value": 2},
+                                                    {"@type": "g:Float", "@value": 2.0},
+                                                    "3"]}))
+        # coerce to list here because Java might return numerics of different types which python won't recognize
+        # see comments of TINKERPOP-1844 for more details
+        assert isinstance(x, list)
+        assert x == list([1, 2, 2.0, "3"])
+        ##
+        x = self.graphson_reader.readObject(
+            json.dumps({"@type": "g:Map",
+                        "@value": ['a', {"@type": "g:Int32", "@value": 1}, 'b', "marko"]}))
+        assert isinstance(x, dict)
+        assert x['a'] == 1
+        assert x['b'] == "marko"
+        assert len(x) == 2
+
+        # BulkSet gets coerced to a List - both have the same behavior
+        x = self.graphson_reader.readObject(
+            json.dumps({"@type": "g:BulkSet",
+                        "@value": ["marko", {"@type": "g:Int64", "@value": 1}, "josh", {"@type": "g:Int64", "@value": 3}]}))
+        assert isinstance(x, list)
+        assert len(x) == 4
+        assert x.count("marko") == 1
+        assert x.count("josh") == 3
+
+    def test_number_input(self):
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "gx:Byte",
+            "@value": 1
+        }))
+        assert isinstance(x, SingleByte)
+        assert 1 == x
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "g:Int32",
+            "@value": 31
+        }))
+        assert isinstance(x, int)
+        assert 31 == x
+        ##
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "g:Int64",
+            "@value": 31
+        }))
+        assert isinstance(x, long)
+        assert long(31) == x
+        ##
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "g:Float",
+            "@value": 31.3
+        }))
+        assert isinstance(x, float)
+        assert 31.3 == x
+        ##
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "g:Double",
+            "@value": 31.2
+        }))
+        assert isinstance(x, float)
+        assert 31.2 == x
+        ##
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "g:Double",
+            "@value": "NaN"
+        }))
+        assert isinstance(x, float)
+        assert math.isnan(x)
+        ##
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "g:Double",
+            "@value": "Infinity"
+        }))
+        assert isinstance(x, float)
+        assert math.isinf(x) and x > 0
+        ##
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "g:Double",
+            "@value": "-Infinity"
+        }))
+        assert isinstance(x, float)
+        assert math.isinf(x) and x < 0
+        ##
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "gx:BigDecimal",
+            "@value": 31.2
+        }))
+        assert isinstance(x, Decimal)
+        assert Decimal(31.2) == x
+        ##
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "gx:BigDecimal",
+            "@value": 123456789987654321123456789987654321
+        }))
+        assert isinstance(x, Decimal)
+        assert Decimal('123456789987654321123456789987654321') == x
+        ##
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "gx:BigDecimal",
+            "@value": "NaN"
+        }))
+        assert isinstance(x, Decimal)
+        assert math.isnan(x)
+        ##
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "gx:BigDecimal",
+            "@value": "Infinity"
+        }))
+        assert isinstance(x, Decimal)
+        assert math.isinf(x) and x > 0
+        ##
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "gx:BigDecimal",
+            "@value": "-Infinity"
+        }))
+        assert isinstance(x, Decimal)
+        assert math.isinf(x) and x < 0
+        ##
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "gx:BigInteger",
+            "@value": 31
+        }))
+        assert isinstance(x, long)
+        assert 31 == x
+        ##
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "gx:BigInteger",
+            "@value": 123456789987654321123456789987654321
+        }))
+        assert isinstance(x, long)
+        assert 123456789987654321123456789987654321 == x
+
+    def test_graph(self):
+        vertex = self.graphson_reader.readObject("""
+        {"@type":"g:Vertex", "@value":{"id":{"@type":"g:Int32","@value":1},"label":"person","outE":{"created":[{"id":{"@type":"g:Int32","@value":9},"inV":{"@type":"g:Int32","@value":3},"properties":{"weight":{"@type":"g:Double","@value":0.4}}}],"knows":[{"id":{"@type":"g:Int32","@value":7},"inV":{"@type":"g:Int32","@value":2},"properties":{"weight":{"@type":"g:Double","@value":0.5}}},{"id":{"@type":"g:Int32","@value":8},"inV":{"@type":"g:Int32","@value":4},"properties":{"weight":{"@type":"g:Double","@value":1.0}}}]},"properties":{"name":[{"id":{"@type":"g:Int64","@value":0},"value":"marko"}],"age":[{"id":{"@type":"g:Int64","@value":1},"value":{"@type":"g:Int32","@value":29}}]}}}""")
+        assert isinstance(vertex, Vertex)
+        assert "person" == vertex.label
+        assert 1 == vertex.id
+        assert isinstance(vertex.id, int)
+        assert vertex == Vertex(1)
+        ##
+        vertex = self.graphson_reader.readObject("""
+        {"@type":"g:Vertex", "@value":{"id":{"@type":"g:Float","@value":45.23}}}""")
+        assert isinstance(vertex, Vertex)
+        assert 45.23 == vertex.id
+        assert isinstance(vertex.id, FloatType)
+        assert "vertex" == vertex.label
+        assert vertex == Vertex(45.23)
+        ##
+        vertex_property = self.graphson_reader.readObject("""
+        {"@type":"g:VertexProperty", "@value":{"id":"anId","label":"aKey","value":true,"vertex":{"@type":"g:Int32","@value":9}}}""")
+        assert isinstance(vertex_property, VertexProperty)
+        assert "anId" == vertex_property.id
+        assert "aKey" == vertex_property.label
+        assert vertex_property.value
+        assert vertex_property.vertex == Vertex(9)
+        ##
+        vertex_property = self.graphson_reader.readObject("""
+        {"@type":"g:VertexProperty", "@value":{"id":{"@type":"g:Int32","@value":1},"label":"name","value":"marko"}}""")
+        assert isinstance(vertex_property, VertexProperty)
+        assert 1 == vertex_property.id
+        assert "name" == vertex_property.label
+        assert "marko" == vertex_property.value
+        assert vertex_property.vertex is None
+        ##
+        edge = self.graphson_reader.readObject("""
+        {"@type":"g:Edge", "@value":{"id":{"@type":"g:Int64","@value":17},"label":"knows","inV":"x","outV":"y","inVLabel":"xLab","properties":{"aKey":"aValue","bKey":true}}}""")
+        # print edge
+        assert isinstance(edge, Edge)
+        assert 17 == edge.id
+        assert "knows" == edge.label
+        assert edge.inV == Vertex("x", "xLabel")
+        assert edge.outV == Vertex("y", "vertex")
+        ##
+        property = self.graphson_reader.readObject("""
+        {"@type":"g:Property", "@value":{"key":"aKey","value":{"@type":"g:Int64","@value":17},"element":{"@type":"g:Edge","@value":{"id":{"@type":"g:Int64","@value":122},"label":"knows","inV":"x","outV":"y","inVLabel":"xLab"}}}}""")
+        # print property
+        assert isinstance(property, Property)
+        assert "aKey" == property.key
+        assert 17 == property.value
+        assert Edge(122, Vertex("x"), "knows", Vertex("y")) == property.element
+
+    def test_path(self):
+        path = self.graphson_reader.readObject(
+            """{"@type":"g:Path","@value":{"labels":{"@type":"g:List","@value":[{"@type":"g:Set","@value":["a"]},{"@type":"g:Set","@value":["b","c"]},{"@type":"g:Set","@value":[]}]},"objects":{"@type":"g:List","@value":[{"@type":"g:Vertex","@value":{"id":{"@type":"g:Int32","@value":1},"label":"person","properties":{"name":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":0},"value":"marko","label":"name"}}],"age":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":1},"value":{"@type":"g:Int32","@value":29},"label":"age"}}]}}},{"@type":"g:Vertex","@value":{"id":{"@type":"g:Int32","@value":3},"label":"software","properties":{"name":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":4},"value":"lop","label":"name"}}],"lang":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":5},"value":"java","label":"lang"}}]}}},"lop"]}}}"""
+        )
+        assert isinstance(path, Path)
+        assert "path[v[1], v[3], lop]" == str(path)
+        assert Vertex(1) == path[0]
+        assert Vertex(1) == path["a"]
+        assert "lop" == path[2]
+        assert 3 == len(path)
+
+    def test_custom_mapping(self):
+
+        # extended mapping
+        class X(object):
+            pass
+
+        type_string = "test:Xtype"
+        override_string = "g:Int64"
+        serdes = Mock()
+
+        reader = GraphSONReader(deserializer_map={type_string: serdes})
+        assert type_string in reader.deserializers
+
+        # base dicts are not modified
+        assert type_string not in gremlin_python.structure.io.graphsonV3d0._deserializers
+
+        x = X()
+        o = reader.toObject({GraphSONUtil.TYPE_KEY: type_string, GraphSONUtil.VALUE_KEY: x})
+        serdes.objectify.assert_called_once_with(x, reader)
+        assert o is serdes.objectify()
+
+        # overridden mapping
+        type_string = "g:Int64"
+        serdes = Mock()
+        reader = GraphSONReader(deserializer_map={type_string: serdes, override_string: serdes})
+        assert gremlin_python.structure.io.graphsonV3d0._deserializers[type_string] is not reader.deserializers[
+            type_string]
+
+        value = 3
+        o = reader.toObject({GraphSONUtil.TYPE_KEY: type_string, GraphSONUtil.VALUE_KEY: value})
+        serdes.objectify.assert_called_once_with(value, reader)
+        assert o is serdes.objectify()
+
+    def test_datetime(self):
+        expected = datetime.datetime(2016, 12, 14, 16, 14, 36, 295000)
+        pts = calendar.timegm(expected.utctimetuple()) + expected.microsecond / 1e6
+        ts = int(round(pts * 1000))
+        dt = self.graphson_reader.readObject(json.dumps({"@type": "g:Date", "@value": ts}))
+        assert isinstance(dt, datetime.datetime)
+        # TINKERPOP-1848
+        assert dt == expected
+
+    def test_timestamp(self):
+        dt = self.graphson_reader.readObject(json.dumps({"@type": "g:Timestamp", "@value": 1481750076295}))
+        assert isinstance(dt, timestamp)
+        assert float(dt) == 1481750076.295
+
+    def test_duration(self):
+        d = self.graphson_reader.readObject(json.dumps({"@type": "gx:Duration", "@value": "PT120H"}))
+        assert isinstance(d, datetime.timedelta)
+        assert d == datetime.timedelta(hours=120)
+
+    def test_uuid(self):
+        prop = self.graphson_reader.readObject(
+            json.dumps({'@type': 'g:UUID', '@value': "41d2e28a-20a4-4ab0-b379-d810dede3786"}))
+        assert isinstance(prop, uuid.UUID)
+        assert str(prop) == '41d2e28a-20a4-4ab0-b379-d810dede3786'
+
+    def test_metrics(self):
+        prop = self.graphson_reader.readObject(
+            json.dumps([{'@type': 'g:TraversalMetrics', '@value': {'dur': 1.468594, 'metrics': [
+                {'@type': 'g:Metrics', '@value': {'dur': 1.380957, 'counts': {}, 'name': 'GraphStep(__.V())', 'annotations': {'percentDur': 94.03259171697556}, 'id': '4.0.0()'}},
+                {'@type': 'g:Metrics', '@value': {'dur': 0.087637, 'counts': {}, 'name': 'ReferenceElementStep', 'annotations': {'percentDur': 5.967408283024444}, 'id': '3.0.0()'}}
+            ]}}]))
+        assert isinstance(prop, list)
+        assert prop == [{'dur': 1.468594, 'metrics': [
+                {'dur': 1.380957, 'counts': {}, 'name': 'GraphStep(__.V())', 'annotations': {'percentDur': 94.03259171697556}, 'id': '4.0.0()'},
+                {'dur': 0.087637, 'counts': {}, 'name': 'ReferenceElementStep', 'annotations': {'percentDur': 5.967408283024444}, 'id': '3.0.0()'}
+                ]}]
+
+    def test_bytebuffer(self):
+        bb = self.graphson_reader.readObject(
+            json.dumps({"@type": "gx:ByteBuffer", "@value": "c29tZSBieXRlcyBmb3IgeW91"}))
+        assert isinstance(bb, ByteBufferType)
+        assert ByteBufferType("c29tZSBieXRlcyBmb3IgeW91", "utf8") == bb
+
+    def test_char(self):
+        c = self.graphson_reader.readObject(json.dumps({"@type": "gx:Char", "@value": "L"}))
+        assert isinstance(c, SingleChar)
+        assert chr(76) == c
+
+    def test_null(self):
+        c = self.graphson_reader.readObject(json.dumps(None))
+        assert c is None
+
+
+class TestGraphSONWriter(object):
+    graphson_writer = GraphSONWriter()
+    graphson_reader = GraphSONReader()
+
+    def test_collections(self):
+        assert {"@type": "g:List", "@value": [{"@type": "g:Int32", "@value": 1},
+                                              {"@type": "g:Int32", "@value": 2},
+                                              {"@type": "g:Int32", "@value": 3}]} == json.loads(
+            self.graphson_writer.writeObject([1, 2, 3]))
+        assert {"@type": "g:Set", "@value": [{"@type": "g:Int32", "@value": 1},
+                                             {"@type": "g:Int32", "@value": 2},
+                                             {"@type": "g:Int32", "@value": 3}]} == json.loads(
+            self.graphson_writer.writeObject(set([1, 2, 3, 3])))
+        assert {"@type": "g:Map",
+                "@value": ['a', {"@type": "g:Int32", "@value": 1}]} == json.loads(
+            self.graphson_writer.writeObject({'a': 1}))
+
+    def test_numbers(self):
+        assert {"@type": "gx:Byte", "@value": 1} == json.loads(self.graphson_writer.writeObject(int.__new__(SingleByte, 1)))
+        assert {"@type": "g:Int64", "@value": 2} == json.loads(self.graphson_writer.writeObject(long(2)))
+        assert {"@type": "g:Int64", "@value": 851401972585122} == json.loads(self.graphson_writer.writeObject(long(851401972585122)))
+        assert {"@type": "g:Int64", "@value": -2} == json.loads(self.graphson_writer.writeObject(long(-2)))
+        assert {"@type": "g:Int64", "@value": -851401972585122} == json.loads(self.graphson_writer.writeObject(long(-851401972585122)))
+        assert {"@type": "g:Int32", "@value": 1} == json.loads(self.graphson_writer.writeObject(1))
+        assert {"@type": "g:Int32", "@value": -1} == json.loads(self.graphson_writer.writeObject(-1))
+        assert {"@type": "g:Int64", "@value": 851401972585122} == json.loads(self.graphson_writer.writeObject(851401972585122))
+        assert {"@type": "g:Double", "@value": 3.2} == json.loads(self.graphson_writer.writeObject(3.2))
+        assert {"@type": "g:Double", "@value": "NaN"} == json.loads(self.graphson_writer.writeObject(float('nan')))
+        assert {"@type": "g:Double", "@value": "Infinity"} == json.loads(self.graphson_writer.writeObject(float('inf')))
+        assert {"@type": "g:Double", "@value": "-Infinity"} == json.loads(self.graphson_writer.writeObject(float('-inf')))
+        assert {"@type": "gx:BigDecimal", "@value": "123456789987654321123456789987654321"} == json.loads(self.graphson_writer.writeObject(Decimal('123456789987654321123456789987654321')))
+        assert {"@type": "gx:BigDecimal", "@value": "NaN"} == json.loads(self.graphson_writer.writeObject(Decimal('nan')))
+        assert {"@type": "gx:BigDecimal", "@value": "Infinity"} == json.loads(self.graphson_writer.writeObject(Decimal('inf')))
+        assert {"@type": "gx:BigDecimal", "@value": "-Infinity"} == json.loads(self.graphson_writer.writeObject(Decimal('-inf')))
+        assert {"@type": "gx:BigInteger", "@value": "123456789987654321123456789987654321"} == json.loads(self.graphson_writer.writeObject(long(123456789987654321123456789987654321)))
+        assert {"@type": "gx:BigInteger", "@value": "123456789987654321123456789987654321"} == json.loads(self.graphson_writer.writeObject(123456789987654321123456789987654321))
+        assert """true""" == self.graphson_writer.writeObject(True)
+
+    def test_P(self):
+        result = {'@type': 'g:P',
+                  '@value': {
+                      'predicate': 'and',
+                      'value': [{
+                          '@type': 'g:P',
+                          '@value': {
+                              'predicate': 'or',
+                              'value': [{
+                                  '@type': 'g:P',
+                                  '@value': {'predicate': 'lt', 'value': 'b'}
+                              },
+                                  {'@type': 'g:P', '@value': {'predicate': 'gt', 'value': 'c'}}
+                              ]
+                          }
+                      },
+                          {'@type': 'g:P', '@value': {'predicate': 'neq', 'value': 'd'}}]}}
+
+        assert result == json.loads(
+            self.graphson_writer.writeObject(P.lt("b").or_(P.gt("c")).and_(P.neq("d"))))
+
+        result = {'@type': 'g:P', '@value': {'predicate': 'within', 'value': {'@type': 'g:List', '@value': [
+            {"@type": "g:Int32", "@value": 1}, {"@type": "g:Int32", "@value": 2}]}}}
+        assert result == json.loads(self.graphson_writer.writeObject(P.within([1, 2])))
+        assert result == json.loads(self.graphson_writer.writeObject(P.within(1, 2)))
+
+        result = {'@type': 'g:P', '@value': {'predicate': 'within', 'value': {'@type': 'g:List', '@value': [
+            {"@type": "g:Int32", "@value": 1}]}}}
+        assert result == json.loads(self.graphson_writer.writeObject(P.within([1])))
+        assert result == json.loads(self.graphson_writer.writeObject(P.within(1)))
+
+    def test_strategies(self):
+        # we have a proxy model for now given that we don't want to have to have g:XXX all registered on the 
+        # Gremlin traversal machine (yet)
+        assert {"@type": "g:SubgraphStrategy", "@value": {}} == json.loads(
+            self.graphson_writer.writeObject(SubgraphStrategy))
+        assert {"@type": "g:SubgraphStrategy", "@value": {
+            "vertices": {"@type": "g:Bytecode", "@value": {"step": [["has", "name", "marko"]]}}}} == json.loads(
+            self.graphson_writer.writeObject(SubgraphStrategy(vertices=__.has("name", "marko"))))
+
+    def test_graph(self):
+        # TODO: this assert is not compatible with python 3 and now that we test with both 2 and 3 it fails
+        assert {"@type": "g:Vertex",
+                "@value": {"id": {"@type": "g:Int64", "@value": 12}, "label": "person"}} == json.loads(
+            self.graphson_writer.writeObject(Vertex(long(12), "person")))
+
+        assert {"@type": "g:Edge", "@value": {"id": {"@type": "g:Int32", "@value": 7},
+                                              "outV": {"@type": "g:Int32", "@value": 0},
+                                              "outVLabel": "person",
+                                              "label": "knows",
+                                              "inV": {"@type": "g:Int32", "@value": 1},
+                                              "inVLabel": "dog"}} == json.loads(
+            self.graphson_writer.writeObject(Edge(7, Vertex(0, "person"), "knows", Vertex(1, "dog"))))
+        assert {"@type": "g:VertexProperty", "@value": {"id": "blah", "label": "keyA", "value": True,
+                                                        "vertex": "stephen"}} == json.loads(
+            self.graphson_writer.writeObject(VertexProperty("blah", "keyA", True, Vertex("stephen"))))
+
+        assert {"@type": "g:Property",
+                "@value": {"key": "name", "value": "marko", "element": {"@type": "g:VertexProperty",
+                                                                        "@value": {
+                                                                            "vertex": "vertexId",
+                                                                            "id": {"@type": "g:Int32", "@value": 1234},
+                                                                            "label": "aKey"}}}} == json.loads(
+            self.graphson_writer.writeObject(
+                Property("name", "marko", VertexProperty(1234, "aKey", 21345, Vertex("vertexId")))))
+
+        vertex = self.graphson_reader.readObject(self.graphson_writer.writeObject(Vertex(1, "person")))
+        assert 1 == vertex.id
+        assert "person" == vertex.label
+
+        edge = self.graphson_reader.readObject(
+            self.graphson_writer.writeObject(Edge(3, Vertex(1, "person"), "knows", Vertex(2, "dog"))))
+        assert "knows" == edge.label
+        assert 3 == edge.id
+        assert 1 == edge.outV.id
+        assert 2 == edge.inV.id
+
+        vertex_property = self.graphson_reader.readObject(
+            self.graphson_writer.writeObject(VertexProperty(1, "age", 32, Vertex(1))))
+        assert 1 == vertex_property.id
+        assert "age" == vertex_property.key
+        assert 32 == vertex_property.value
+
+        property = self.graphson_reader.readObject(self.graphson_writer.writeObject(Property("age", 32.2, Edge(1,Vertex(2),"knows",Vertex(3)))))
+        assert "age" == property.key
+        assert 32.2 == property.value
+
+    def test_custom_mapping(self):
+        # extended mapping
+        class X(object):
+            pass
+
+        serdes = Mock()
+        writer = GraphSONWriter(serializer_map={X: serdes})
+        assert X in writer.serializers
+
+        # base dicts are not modified
+        assert X not in gremlin_python.structure.io.graphsonV3d0._serializers
+
+        obj = X()
+        d = writer.toDict(obj)
+        serdes.dictify.assert_called_once_with(obj, writer)
+        assert d is serdes.dictify()
+
+        # overridden mapping
+        serdes = Mock()
+        writer = GraphSONWriter(serializer_map={int: serdes})
+        assert gremlin_python.structure.io.graphsonV3d0._serializers[int] is not writer.serializers[int]
+
+        value = 3
+        d = writer.toDict(value)
+        serdes.dictify.assert_called_once_with(value, writer)
+        assert d is serdes.dictify()
+
+    def test_write_long(self):
+        mapping = self.graphson_writer.toDict(1)
+        assert mapping['@type'] == 'g:Int32'
+        assert mapping['@value'] == 1
+
+        mapping = self.graphson_writer.toDict(long(1))
+        assert mapping['@type'] == 'g:Int64'
+        assert mapping['@value'] == 1
+
+    def test_datetime(self):
+        expected = json.dumps({"@type": "g:Date", "@value": 1481750076295}, separators=(',', ':'))
+        dt = datetime.datetime.utcfromtimestamp(1481750076295 / 1000.0)
+        output = self.graphson_writer.writeObject(dt)
+        assert expected == output
+
+    def test_timestamp(self):
+        expected = json.dumps({"@type": "g:Timestamp", "@value": 1481750076295}, separators=(',', ':'))
+        ts = timestamp(1481750076295 / 1000.0)
+        output = self.graphson_writer.writeObject(ts)
+        assert expected == output
+
+    def test_duration(self):
+        expected = json.dumps({"@type": "gx:Duration", "@value": "P5D"}, separators=(',', ':'))
+        d = datetime.timedelta(hours=120)
+        output = self.graphson_writer.writeObject(d)
+        assert expected == output
+
+    def test_uuid(self):
+        expected = json.dumps({'@type': 'g:UUID', '@value': "41d2e28a-20a4-4ab0-b379-d810dede3786"}, separators=(',', ':'))
+        prop = uuid.UUID("41d2e28a-20a4-4ab0-b379-d810dede3786")
+        output = self.graphson_writer.writeObject(prop)
+        assert expected == output
+
+    def test_bytebuffer(self):
+        expected = json.dumps({'@type': 'gx:ByteBuffer', '@value': 'c29tZSBieXRlcyBmb3IgeW91'}, separators=(',', ':'))
+        bb = ByteBufferType("c29tZSBieXRlcyBmb3IgeW91", "utf8")
+        output = self.graphson_writer.writeObject(bb)
+        assert expected == output
+
+    def test_char(self):
+        expected = json.dumps({'@type': 'gx:Char', '@value': 'L'}, separators=(',', ':'))
+        c = str.__new__(SingleChar, chr(76))
+        output = self.graphson_writer.writeObject(c)
+        assert expected == output
diff --git a/gremlin-python/src/main/python/tests/structure/test_graph.py b/gremlin-python/src/main/python/tests/structure/test_graph.py
new file mode 100644
index 0000000..0937e39
--- /dev/null
+++ b/gremlin-python/src/main/python/tests/structure/test_graph.py
@@ -0,0 +1,111 @@
+#
+# 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.
+#
+
+__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
+
+from gremlin_python.statics import long
+from gremlin_python.structure.graph import Edge
+from gremlin_python.structure.graph import Property
+from gremlin_python.structure.graph import Vertex
+from gremlin_python.structure.graph import VertexProperty
+from gremlin_python.structure.graph import Path
+
+
+class TestGraph(object):
+    def test_graph_objects(self):
+        vertex = Vertex(1)
+        assert "v[1]" == str(vertex)
+        assert "vertex" == vertex.label
+        assert "person" == Vertex(1, "person").label
+        assert vertex == Vertex(1)
+        #
+        edge = Edge(2, Vertex(1), "said", Vertex("hello", "phrase"))
+        assert "e[2][1-said->hello]" == str(edge)
+        assert Vertex(1) == edge.outV
+        assert Vertex("hello") == edge.inV
+        assert "said" == edge.label
+        assert "phrase" == edge.inV.label
+        assert edge.inV != edge.outV
+        #
+        vertex_property = VertexProperty(long(24), "name", "marko", Vertex(1))
+        assert "vp[name->marko]" == str(vertex_property)
+        assert "name" == vertex_property.label
+        assert "name" == vertex_property.key
+        assert "marko" == vertex_property.value
+        assert long(24) == vertex_property.id
+        assert Vertex(1) == vertex_property.vertex
+        assert isinstance(vertex_property.id, long)
+        assert vertex_property == VertexProperty(long(24), "name", "marko", Vertex(1))
+        #
+        property = Property("age", 29, Vertex(1))
+        assert "p[age->29]" == str(property)
+        assert "age" == property.key
+        assert 29 == property.value
+        assert Vertex(1) == property.element
+        assert isinstance(property.value, int)
+        assert property == Property("age", 29, Vertex(1))
+        #
+        for i in [vertex, edge, vertex_property, property]:
+            for j in [vertex, edge, vertex_property, property]:
+                if type(i) != type(j):
+                    assert i != j
+                else:
+                    assert i == j
+                    assert i.__hash__() == hash(i)
+
+    def test_path(self):
+        path = Path([set(["a", "b"]), set(["c", "b"]), set([])], [1, Vertex(1), "hello"])
+        assert "path[1, v[1], hello]" == str(path)
+        assert 1 == path["a"]
+        assert Vertex(1) == path["c"]
+        assert [1, Vertex(1)] == path["b"]
+        assert path[0] == 1
+        assert path[1] == Vertex(1)
+        assert path[2] == "hello"
+        assert 3 == len(path)
+        assert "hello" in path
+        assert "goodbye" not in path
+        assert Vertex(1) in path
+        assert Vertex(123) not in path
+        #
+        try:
+            temp = path[3]
+            raise Exception("Accessing beyond the list index should throw an index error")
+        except IndexError:
+            pass
+        #
+        try:
+            temp = path["zz"]
+            raise Exception("Accessing nothing should throw a key error")
+        except KeyError:
+            pass
+        #
+        try:
+            temp = path[1:2]
+            raise Exception("Accessing using slices should throw a type error")
+        except TypeError:
+            pass
+        #
+        assert path == path
+        assert hash(path) == hash(path)
+        path2 = Path([set(["a", "b"]), set(["c", "b"]), set([])], [1, Vertex(1), "hello"])
+        assert path == path2
+        assert hash(path) == hash(path2)
+        assert path != Path([set(["a"]), set(["c", "b"]), set([])], [1, Vertex(1), "hello"])
+        assert path != Path([set(["a", "b"]), set(["c", "b"]), set([])], [3, Vertex(1), "hello"])
diff --git a/gremlin-python/src/main/jython/tests/test_statics.py b/gremlin-python/src/main/python/tests/test_statics.py
similarity index 100%
rename from gremlin-python/src/main/jython/tests/test_statics.py
rename to gremlin-python/src/main/python/tests/test_statics.py
diff --git a/gremlin-python/src/main/resources/META-INF/services/javax.script.ScriptEngineFactory b/gremlin-python/src/main/resources/META-INF/services/javax.script.ScriptEngineFactory
deleted file mode 100644
index 3dda102..0000000
--- a/gremlin-python/src/main/resources/META-INF/services/javax.script.ScriptEngineFactory
+++ /dev/null
@@ -1,20 +0,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.
-#
-
-org.apache.tinkerpop.gremlin.python.jsr223.GremlinJythonScriptEngineFactory
\ No newline at end of file
diff --git a/gremlin-python/src/main/resources/META-INF/services/org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngineFactory b/gremlin-python/src/main/resources/META-INF/services/org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngineFactory
deleted file mode 100644
index 92f4825..0000000
--- a/gremlin-python/src/main/resources/META-INF/services/org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngineFactory
+++ /dev/null
@@ -1 +0,0 @@
-org.apache.tinkerpop.gremlin.python.jsr223.GremlinJythonScriptEngineFactory
\ No newline at end of file
diff --git a/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/GremlinJythonScriptEngineTest.java b/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/GremlinJythonScriptEngineTest.java
deleted file mode 100644
index 2c4e5bc..0000000
--- a/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/GremlinJythonScriptEngineTest.java
+++ /dev/null
@@ -1,105 +0,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.
- */
-
-package org.apache.tinkerpop.gremlin.python.jsr223;
-
-import org.apache.tinkerpop.gremlin.jsr223.DefaultGremlinScriptEngineManager;
-import org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngineManager;
-import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
-import org.apache.tinkerpop.gremlin.structure.Column;
-import org.apache.tinkerpop.gremlin.structure.T;
-import org.apache.tinkerpop.gremlin.structure.VertexProperty;
-import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerFactory;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import javax.script.ScriptContext;
-import javax.script.ScriptEngine;
-import javax.script.ScriptEngineManager;
-import java.math.BigInteger;
-import java.util.Arrays;
-import java.util.HashSet;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.core.IsInstanceOf.instanceOf;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-/**
- * @author Marko A. Rodriguez (http://markorodriguez.com)
- */
-@Ignore
-public class GremlinJythonScriptEngineTest {
-
-    @Test
-    public void shouldGetEngineByName() throws Exception {
-        final ScriptEngine engine = new DefaultGremlinScriptEngineManager().getEngineByName("gremlin-jython");
-        assertNotNull(engine);
-        assertTrue(engine instanceof GremlinJythonScriptEngine);
-        assertEquals(3, engine.eval("1+2"));
-    }
-
-    @Test
-    public void shouldHaveCoreImports() throws Exception {
-        final ScriptEngine engine = new DefaultGremlinScriptEngineManager().getEngineByName("gremlin-jython");
-        assertThat(engine.eval("Graph"), instanceOf(Class.class));
-        assertThat(engine.eval("__"), instanceOf(Class.class));
-        assertThat(engine.eval("T"), instanceOf(Class.class));
-        assertThat(engine.eval("label"), instanceOf(T.class));
-        assertThat(engine.eval("T.label"), instanceOf(T.class));
-        assertEquals(SackFunctions.Barrier.class, engine.eval("Barrier"));
-        assertEquals(SackFunctions.Barrier.normSack, engine.eval("Barrier.normSack"));
-        assertEquals(Column.class, engine.eval("Column"));
-        assertEquals(Column.values, engine.eval("Column.valueOf(\'values\')"));
-        assertEquals(VertexProperty.Cardinality.class, engine.eval("Cardinality"));
-        assertEquals(VertexProperty.Cardinality.single, engine.eval("Cardinality.valueOf(\'single\')"));
-        assertTrue(engine.eval("out()") instanceof GraphTraversal);
-        assertTrue(engine.eval("__.out()") instanceof GraphTraversal);
-        assertTrue(engine.eval("__.property(VertexProperty.Cardinality.single, 'name','marko')") instanceof GraphTraversal);
-        assertTrue(engine.eval("__.property(Cardinality.single, 'name','marko')") instanceof GraphTraversal);
-    }
-
-
-    @Test
-    public void shouldSupportJavaBasedGraphTraversal() throws Exception {
-        final ScriptEngine engine = new DefaultGremlinScriptEngineManager().getEngineByName("gremlin-jython");
-        engine.getBindings(ScriptContext.ENGINE_SCOPE).put("graph", TinkerFactory.createModern());
-        engine.eval("g = graph.traversal()");
-        assertEquals(new HashSet<>(Arrays.asList("ripple", "lop")), engine.eval("g.V().repeat(out()).times(2).values('name').toSet()"));
-        assertEquals(new HashSet<>(Arrays.asList("ripple", "lop")), engine.eval("g.V().repeat(__.out()).times(2).values('name').toSet()"));
-        assertEquals(new HashSet<>(Arrays.asList("ripple", "lop")), engine.eval("g.V().repeat(out()).times(2).name.toSet()"));
-        assertEquals(new HashSet<>(Arrays.asList("ripple", "lop")), engine.eval("g.V().repeat(__.out()).times(2).name.toSet()"));
-        assertEquals(new HashSet<>(Arrays.asList("ripple", "lop")), engine.eval("g.V().repeat(__.out()).times(2)[0:2].name.toSet()"));
-        assertEquals(new HashSet<>(Arrays.asList("ripple", "lop")), engine.eval("g.V().repeat(__.out()).times(2).name[0:3].toSet()"));
-    }
-
-    @Test
-    public void shouldSupportSugarMethods() throws Exception {
-        final ScriptEngine engine = new DefaultGremlinScriptEngineManager().getEngineByName("gremlin-jython");
-        engine.getBindings(ScriptContext.ENGINE_SCOPE).put("graph", TinkerFactory.createModern());
-        engine.eval("g = graph.traversal()");
-        assertEquals(new HashSet<>(Arrays.asList("ripple", "lop")), engine.eval("g.V().repeat(__.out()).times(2)[0:2].name.toSet()"));
-        assertEquals(new HashSet<>(Arrays.asList("ripple", "lop")), engine.eval("g.V().repeat(__.out()).times(2).name[0:3].toSet()"));
-        assertEquals(BigInteger.valueOf(1), engine.eval("g.V().repeat(__.out()).times(2).name[0:1].count().next()"));
-        assertEquals(BigInteger.valueOf(1), engine.eval("g.V().repeat(__.out()).times(2).name[0].count().next()"));
-        assertEquals(BigInteger.valueOf(0), engine.eval("g.V().repeat(__.out()).times(2).name[3].count().next()"));
-    }
-}
diff --git a/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/JythonScriptEngineSetup.java b/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/JythonScriptEngineSetup.java
deleted file mode 100644
index bfbd8c4..0000000
--- a/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/JythonScriptEngineSetup.java
+++ /dev/null
@@ -1,63 +0,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.
- */
-
-package org.apache.tinkerpop.gremlin.python.jsr223;
-
-import org.apache.tinkerpop.gremlin.jsr223.ScriptEngineCache;
-import org.python.jsr223.PyScriptEngine;
-
-import javax.script.ScriptException;
-
-/**
- * @author Marko A. Rodriguez (http://markorodriguez.com)
- */
-public class JythonScriptEngineSetup {
-
-    private JythonScriptEngineSetup() {
-    }
-
-    public static void setup() {
-        setup((PyScriptEngine) ScriptEngineCache.get("jython"));
-    }
-
-    public static PyScriptEngine setup(final PyScriptEngine jythonEngine) {
-        try {
-            jythonEngine.eval("import gremlin_python.statics");
-            jythonEngine.eval("from gremlin_python.process.traversal import *");
-            jythonEngine.eval("from gremlin_python.process.graph_traversal import *");
-            jythonEngine.eval("from gremlin_python.process.graph_traversal import __");
-            // jythonEngine.eval("from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection");
-            jythonEngine.eval("from gremlin_python.process.traversal import Bytecode");
-            jythonEngine.eval("from gremlin_python.structure.graph import Graph");
-            jythonEngine.eval("from gremlin_python.structure.graph import Vertex");
-            jythonEngine.eval("from gremlin_python.structure.graph import Edge");
-            jythonEngine.eval("from gremlin_python.structure.graph import VertexProperty");
-            jythonEngine.eval("from gremlin_python.structure.graph import Property");
-            jythonEngine.eval("import gremlin_python.structure.io.graphsonV2d0");
-            jythonEngine.eval("import gremlin_python.structure.io.graphsonV3d0");
-            jythonEngine.eval("graphsonV2d0_reader = gremlin_python.structure.io.graphsonV2d0.GraphSONReader()");
-            jythonEngine.eval("graphsonV2d0_writer = gremlin_python.structure.io.graphsonV2d0.GraphSONWriter()");
-            jythonEngine.eval("graphsonV3d0_reader = gremlin_python.structure.io.graphsonV3d0.GraphSONReader()");
-            jythonEngine.eval("graphsonV3d0_writer = gremlin_python.structure.io.graphsonV3d0.GraphSONWriter()");
-            return jythonEngine;
-        } catch (final ScriptException e) {
-            throw new IllegalStateException(e.getMessage(), e);
-        }
-    }
-}
diff --git a/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/JythonTranslatorTest.java b/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/JythonTranslatorTest.java
deleted file mode 100644
index 5e9b31a..0000000
--- a/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/JythonTranslatorTest.java
+++ /dev/null
@@ -1,124 +0,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.
- */
-
-package org.apache.tinkerpop.gremlin.python.jsr223;
-
-import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
-import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy;
-import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.TranslationStrategy;
-import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy;
-import org.apache.tinkerpop.gremlin.structure.Vertex;
-import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerFactory;
-import org.apache.tinkerpop.gremlin.util.function.Lambda;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.hasLabel;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-
-/**
- * @author Marko A. Rodriguez (http://markorodriguez.com)
- * @author Stephen Mallette (http://stephen.genoprime.com)
- */
-public class JythonTranslatorTest {
-
-    @Test
-    public void shouldSupportStringSupplierLambdas() throws Exception {
-        GraphTraversalSource g = TinkerFactory.createModern().traversal();
-        g = g.withStrategies(new TranslationStrategy(g, JythonTranslator.of("g"), false));
-        final GraphTraversal.Admin<Vertex, Integer> t = g.withSideEffect("lengthSum", 0).withSack(1)
-                .V()
-                .filter(Lambda.predicate("x : x.get().label() == 'person'"))
-                .flatMap(Lambda.function("lambda x : x.get().vertices(Direction.OUT)"))
-                .map(Lambda.<Traverser<Object>, Integer>function("lambda x : len(x.get().value('name'))"))
-                .sideEffect(Lambda.consumer(" x : x.sideEffects(\"lengthSum\", x.sideEffects('lengthSum') + x.get())    "))
-                .order().by(Lambda.comparator("  lambda a,b : 0 if a == b else 1 if a > b else -1"))
-                .sack(Lambda.biFunction("lambda a,b : a + b"))
-                .asAdmin();
-        final List<Integer> sacks = new ArrayList<>();
-        final List<Integer> lengths = new ArrayList<>();
-        while (t.hasNext()) {
-            final Traverser.Admin<Integer> traverser = t.nextTraverser();
-            sacks.add(traverser.sack());
-            lengths.add(traverser.get());
-        }
-        assertFalse(t.hasNext());
-        //
-        assertEquals(6, lengths.size());
-        assertEquals(3, lengths.get(0).intValue());
-        assertEquals(3, lengths.get(1).intValue());
-        assertEquals(3, lengths.get(2).intValue());
-        assertEquals(4, lengths.get(3).intValue());
-        assertEquals(5, lengths.get(4).intValue());
-        assertEquals(6, lengths.get(5).intValue());
-        ///
-        assertEquals(6, sacks.size());
-        assertEquals(4, sacks.get(0).intValue());
-        assertEquals(4, sacks.get(1).intValue());
-        assertEquals(4, sacks.get(2).intValue());
-        assertEquals(5, sacks.get(3).intValue());
-        assertEquals(6, sacks.get(4).intValue());
-        assertEquals(7, sacks.get(5).intValue());
-        //
-        assertEquals(24, t.getSideEffects().<Number>get("lengthSum").intValue());
-    }
-
-    @Test
-    public void shouldHaveValidToString() {
-        assertEquals("translator[h:gremlin-jython]", JythonTranslator.of("h").toString());
-    }
-
-    @Test
-    public void shouldTranslateToJythonAndNotPython() throws Exception {
-        // the jython translation bind "g" to java classes and thus does not require the strict python syntax which
-        // converts steps like as() to as_(). if those steps are converted then the traversal does not evaluate
-        // properly in the python engine. not much of an assertion here to worry about - just need to ensure that
-        // the traversal with such steps evaluates to success
-        GraphTraversalSource g = TinkerFactory.createModern().traversal();
-        g = g.withStrategies(new TranslationStrategy(g, JythonTranslator.of("g"), false));
-        final List<Object> o = g.V().has("name").
-                match(__.as("x").label().as("lbl"),
-                        __.as("x").id().as("id")).
-                select("lbl", "id").
-                                 map(Lambda.function("lambda x: type(x.get())")).toList();
-
-        assertEquals(6, o.size());
-    }
-
-    @Test
-    @Ignore("TINKERPOP-1898 - ultimately seems to be a problem with jython and varargs - doesn't act consistently")
-    public void shouldTranslateToJythonWhenUsingLambdasAndStrategies() throws Exception {
-        // the jython translation kicks in when you add a lambda so ensure that it translates when strategies are
-        // present
-        GraphTraversalSource g = TinkerFactory.createModern().traversal();
-        g = g.withStrategies(new TranslationStrategy(g, JythonTranslator.of("g"), false));
-        final List<Object> o = g.withStrategies(ReadOnlyStrategy.instance(),
-                                                SubgraphStrategy.build().checkAdjacentVertices(false).vertices(hasLabel("person")).create()).
-                                 V().has("name").map(Lambda.function("lambda x: type(x.get())")).toList();
-
-        assertEquals(4, o.size());
-    }
-}
diff --git a/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonComputerProvider.java b/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonComputerProvider.java
deleted file mode 100644
index 7ccc4c6..0000000
--- a/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonComputerProvider.java
+++ /dev/null
@@ -1,36 +0,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.
- */
-
-package org.apache.tinkerpop.gremlin.python.jsr223;
-
-import org.apache.tinkerpop.gremlin.GraphProvider;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
-import org.apache.tinkerpop.gremlin.structure.Graph;
-import org.apache.tinkerpop.gremlin.tinkergraph.process.computer.TinkerGraphComputer;
-
-/**
- * @author Marko A. Rodriguez (http://markorodriguez.com)
- */
-@GraphProvider.Descriptor(computer = TinkerGraphComputer.class)
-public class PythonComputerProvider extends PythonProvider {
-
-    public GraphTraversalSource traversal(final Graph graph) {
-        return super.traversal(graph).withComputer();
-    }
-}
diff --git a/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonGraphSONJavaTranslator.java b/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonGraphSONJavaTranslator.java
deleted file mode 100644
index 6c77867..0000000
--- a/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonGraphSONJavaTranslator.java
+++ /dev/null
@@ -1,118 +0,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.
- */
-
-package org.apache.tinkerpop.gremlin.python.jsr223;
-
-import org.apache.tinkerpop.gremlin.jsr223.JavaTranslator;
-import org.apache.tinkerpop.gremlin.jsr223.ScriptEngineCache;
-import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
-import org.apache.tinkerpop.gremlin.process.traversal.Translator;
-import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
-import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
-import org.apache.tinkerpop.gremlin.process.traversal.util.BytecodeHelper;
-import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper;
-import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONReader;
-import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONVersion;
-import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONWriter;
-import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONXModuleV2d0;
-import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONXModuleV3d0;
-import org.apache.tinkerpop.shaded.jackson.core.JsonFactory;
-import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
-
-import javax.script.Bindings;
-import javax.script.ScriptContext;
-import javax.script.ScriptEngine;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.util.Map;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * @author Marko A. Rodriguez (http://markorodriguez.com)
- */
-final class PythonGraphSONJavaTranslator<S extends TraversalSource, T extends Traversal.Admin<?, ?>> implements Translator.StepTranslator<S, T> {
-
-    private final boolean IS_TESTING = Boolean.valueOf(System.getProperty("is.testing", "false"));
-    private final PythonTranslator pythonTranslator;
-    private final JavaTranslator<S, T> javaTranslator;
-    private final GraphSONReader reader;
-    private final GraphSONWriter writer;
-    private final GraphSONVersion version;
-
-    public PythonGraphSONJavaTranslator(final PythonTranslator pythonTranslator, final JavaTranslator<S, T> javaTranslator, final GraphSONVersion version) {
-        this.pythonTranslator = pythonTranslator;
-        this.javaTranslator = javaTranslator;
-        this.version = version;
-        this.reader = GraphSONReader.build().mapper(
-                GraphSONMapper.build().addCustomModule(version.equals(GraphSONVersion.V2_0) ?
-                        GraphSONXModuleV2d0.build().create(false) :
-                        GraphSONXModuleV3d0.build().create(false))
-                        .version(version).create()).create();
-        this.writer = GraphSONWriter.build().mapper(
-                GraphSONMapper.build().addCustomModule(version.equals(GraphSONVersion.V2_0) ?
-                        GraphSONXModuleV2d0.build().create(false) :
-                        GraphSONXModuleV3d0.build().create(false))
-                        .version(version).create()).create();
-    }
-
-    @Override
-    public S getTraversalSource() {
-        return this.javaTranslator.getTraversalSource();
-    }
-
-    @Override
-    public String getTargetLanguage() {
-        return this.javaTranslator.getTargetLanguage();
-    }
-
-    @Override
-    public T translate(final Bytecode bytecode) {
-        try {
-            final ScriptEngine jythonEngine = ScriptEngineCache.get("jython");
-            final Bindings bindings = jythonEngine.createBindings();
-            bindings.putAll(jythonEngine.getBindings(ScriptContext.ENGINE_SCOPE));
-            bindings.put(this.pythonTranslator.getTraversalSource(), jythonEngine.eval("Graph().traversal()"));
-            bindings.putAll(bytecode.getBindings());
-            final String translatedGraphSONBytecode = jythonEngine.eval((this.version.equals(GraphSONVersion.V2_0) ?
-                    "graphsonV2d0_writer" :
-                    "graphsonV3d0_writer") +
-                    ".writeObject(" + this.pythonTranslator.translate(bytecode) + ")", bindings).toString();
-            if (IS_TESTING) {
-                // verify that the GraphSON sent to Python is the same as the GraphSON returned by Python
-                final ByteArrayOutputStream output = new ByteArrayOutputStream();
-                BytecodeHelper.removeBindings(bytecode); // this is because bindings are variables that get converted to values at translation
-                BytecodeHelper.detachElements(bytecode); // this is to get the minimal necessary representation
-                this.writer.writeObject(output, bytecode);
-                final String originalGraphSONBytecode = new String(output.toByteArray());
-                final ObjectMapper mapper = new ObjectMapper(new JsonFactory());
-                // System.out.println(originalGraphSONBytecode + "\n" + translatedGraphSONBytecode + "\n\n");
-                final Map<String, Object> original = mapper.readValue(originalGraphSONBytecode, Map.class);
-                final Map<String, Object> translated = mapper.readValue(translatedGraphSONBytecode, Map.class);
-                assertEquals(originalGraphSONBytecode.length(), translatedGraphSONBytecode.length());
-                assertEquals(original, translated);
-            }
-            return this.javaTranslator.translate(this.reader.readObject(new ByteArrayInputStream(translatedGraphSONBytecode.getBytes()), Bytecode.class));
-
-        } catch (final Exception e) {
-            throw new IllegalArgumentException(e.getMessage(), e);
-        }
-
-    }
-}
diff --git a/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonGremlinScriptEngineTest.java b/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonGremlinScriptEngineTest.java
deleted file mode 100644
index 9313717..0000000
--- a/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonGremlinScriptEngineTest.java
+++ /dev/null
@@ -1,33 +0,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.
- */
-package org.apache.tinkerpop.gremlin.python.jsr223;
-
-import org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngineSuite;
-import org.apache.tinkerpop.gremlin.jsr223.ScriptEngineToTest;
-import org.junit.Ignore;
-import org.junit.runner.RunWith;
-
-/**
- * @author Stephen Mallette (http://stephen.genoprime.com)
- */
-@Ignore
-@RunWith(GremlinScriptEngineSuite.class)
-@ScriptEngineToTest(scriptEngineName = "gremlin-jython")
-public class PythonGremlinScriptEngineTest {
-}
diff --git a/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonProcessComputerTest.java b/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonProcessComputerTest.java
deleted file mode 100644
index fc53bbd..0000000
--- a/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonProcessComputerTest.java
+++ /dev/null
@@ -1,35 +0,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.
- */
-
-package org.apache.tinkerpop.gremlin.python.jsr223;
-
-import org.apache.tinkerpop.gremlin.GraphProviderClass;
-import org.apache.tinkerpop.gremlin.process.ProcessComputerSuite;
-import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
-import org.junit.Ignore;
-import org.junit.runner.RunWith;
-
-/**
- * @author Marko A. Rodriguez (http://markorodriguez.com)
- */
-@Ignore
-@RunWith(ProcessComputerSuite.class)
-@GraphProviderClass(provider = PythonComputerProvider.class, graph = TinkerGraph.class)
-public class PythonProcessComputerTest {
-}
diff --git a/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonProcessStandardTest.java b/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonProcessStandardTest.java
deleted file mode 100644
index 21bfb78..0000000
--- a/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonProcessStandardTest.java
+++ /dev/null
@@ -1,35 +0,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.
- */
-
-package org.apache.tinkerpop.gremlin.python.jsr223;
-
-import org.apache.tinkerpop.gremlin.GraphProviderClass;
-import org.apache.tinkerpop.gremlin.process.ProcessStandardSuite;
-import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
-import org.junit.Ignore;
-import org.junit.runner.RunWith;
-
-/**
- * @author Marko A. Rodriguez (http://markorodriguez.com)
- */
-@Ignore
-@RunWith(ProcessStandardSuite.class)
-@GraphProviderClass(provider = PythonProvider.class, graph = TinkerGraph.class)
-public class PythonProcessStandardTest {
-}
diff --git a/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonProvider.java b/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonProvider.java
deleted file mode 100644
index 345aa65..0000000
--- a/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonProvider.java
+++ /dev/null
@@ -1,158 +0,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.
- */
-
-package org.apache.tinkerpop.gremlin.python.jsr223;
-
-import org.apache.commons.configuration.Configuration;
-import org.apache.tinkerpop.gremlin.AbstractGraphProvider;
-import org.apache.tinkerpop.gremlin.LoadGraphWith;
-import org.apache.tinkerpop.gremlin.TestHelper;
-import org.apache.tinkerpop.gremlin.jsr223.JavaTranslator;
-import org.apache.tinkerpop.gremlin.jsr223.ScriptEngineCache;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
-import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.TranslationStrategy;
-import org.apache.tinkerpop.gremlin.structure.Graph;
-import org.apache.tinkerpop.gremlin.structure.VertexProperty;
-import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONVersion;
-import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerEdge;
-import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerElement;
-import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
-import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraphVariables;
-import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerProperty;
-import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerVertex;
-import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerVertexProperty;
-
-import javax.script.ScriptException;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Random;
-import java.util.Set;
-
-/**
- * @author Marko A. Rodriguez (http://markorodriguez.com)
- */
-@Graph.OptOut(
-        test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.ProgramTest",
-        method = "*",
-        reason = "Reason requires investigation")
-@Graph.OptOut(
-        test = "org.apache.tinkerpop.gremlin.process.traversal.TraversalInterruptionTest",
-        method = "*",
-        reason = "Reason requires investigation")
-@Graph.OptOut(
-        test = "org.apache.tinkerpop.gremlin.process.traversal.TraversalInterruptionComputerTest",
-        method = "*",
-        reason = "Reason requires investigation")
-@Graph.OptOut(
-        test = "org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.EventStrategyProcessTest",
-        method = "*",
-        reason = "Strategy not properly supported by Bytecode based traversals")
-@Graph.OptOut(
-        test = "org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.ElementIdStrategyProcessTest",
-        method = "*",
-        reason = "Strategy not properly supported by Bytecode based traversals")
-public class PythonProvider extends AbstractGraphProvider {
-
-    protected static final boolean IMPORT_STATICS = new Random().nextBoolean();
-
-
-    static {
-        JythonScriptEngineSetup.setup();
-    }
-
-    private static final Set<Class> IMPLEMENTATION = new HashSet<Class>() {{
-        add(TinkerEdge.class);
-        add(TinkerElement.class);
-        add(TinkerGraph.class);
-        add(TinkerGraphVariables.class);
-        add(TinkerProperty.class);
-        add(TinkerVertex.class);
-        add(TinkerVertexProperty.class);
-    }};
-
-    @Override
-    public Map<String, Object> getBaseConfiguration(final String graphName, final Class<?> test, final String testMethodName,
-                                                    final LoadGraphWith.GraphData loadGraphWith) {
-        final TinkerGraph.DefaultIdManager idManager = selectIdMakerFromGraphData(loadGraphWith);
-        final String idMaker = (idManager.equals(TinkerGraph.DefaultIdManager.ANY) ? selectIdMakerFromGraphData(loadGraphWith) : idManager).name();
-        return new HashMap<String, Object>() {{
-            put(Graph.GRAPH, TinkerGraph.class.getName());
-            put(TinkerGraph.GREMLIN_TINKERGRAPH_VERTEX_ID_MANAGER, idMaker);
-            put(TinkerGraph.GREMLIN_TINKERGRAPH_EDGE_ID_MANAGER, idMaker);
-            put(TinkerGraph.GREMLIN_TINKERGRAPH_VERTEX_PROPERTY_ID_MANAGER, idMaker);
-            if (loadGraphWith == LoadGraphWith.GraphData.CREW)
-                put(TinkerGraph.GREMLIN_TINKERGRAPH_DEFAULT_VERTEX_PROPERTY_CARDINALITY, VertexProperty.Cardinality.list.name());
-        }};
-    }
-
-    @Override
-    public void clear(final Graph graph, final Configuration configuration) throws Exception {
-        if (graph != null) graph.close();
-    }
-
-    @Override
-    public Set<Class> getImplementations() {
-        return IMPLEMENTATION;
-    }
-
-    /**
-     * Test that load with specific graph data can be configured with a specific id manager as the data type to
-     * be used in the test for that graph is known.
-     */
-    protected TinkerGraph.DefaultIdManager selectIdMakerFromGraphData(final LoadGraphWith.GraphData loadGraphWith) {
-        if (null == loadGraphWith) return TinkerGraph.DefaultIdManager.ANY;
-        if (loadGraphWith.equals(LoadGraphWith.GraphData.CLASSIC))
-            return TinkerGraph.DefaultIdManager.INTEGER;
-        else if (loadGraphWith.equals(LoadGraphWith.GraphData.MODERN))
-            return TinkerGraph.DefaultIdManager.INTEGER;
-        else if (loadGraphWith.equals(LoadGraphWith.GraphData.CREW))
-            return TinkerGraph.DefaultIdManager.INTEGER;
-        else if (loadGraphWith.equals(LoadGraphWith.GraphData.GRATEFUL))
-            return TinkerGraph.DefaultIdManager.INTEGER;
-        else
-            throw new IllegalStateException(String.format("Need to define a new %s for %s", TinkerGraph.IdManager.class.getName(), loadGraphWith.name()));
-    }
-
-    /////////////////////////////
-    /////////////////////////////
-    /////////////////////////////
-
-    @Override
-    public GraphTraversalSource traversal(final Graph graph) {
-        if ((Boolean) graph.configuration().getProperty("skipTest"))
-            return graph.traversal();
-            //throw new VerificationException("This test current does not work with Gremlin-Python", EmptyTraversal.instance());
-        else {
-            try {
-                ScriptEngineCache.get("jython").eval(IMPORT_STATICS ?
-                        "statics.load_statics(globals())" :
-                        "statics.unload_statics(globals())");
-            } catch (final ScriptException e) {
-                throw new IllegalStateException(e.getMessage(), e);
-            }
-            final GraphTraversalSource g = graph.traversal();
-            return g.withStrategies(new TranslationStrategy(g,
-                    new PythonGraphSONJavaTranslator<>(
-                            PythonTranslator.of("g", IMPORT_STATICS),
-                            JavaTranslator.of(g),
-                            TestHelper.RANDOM.nextBoolean() ? GraphSONVersion.V2_0 : GraphSONVersion.V3_0), true));
-        }
-    }
-}
diff --git a/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/structure/io/graphson/GraphSONReaderTest.java b/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/structure/io/graphson/GraphSONReaderTest.java
deleted file mode 100644
index d1e37b6..0000000
--- a/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/structure/io/graphson/GraphSONReaderTest.java
+++ /dev/null
@@ -1,155 +0,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.
- */
-
-package org.apache.tinkerpop.gremlin.python.structure.io.graphson;
-
-import org.apache.tinkerpop.gremlin.process.remote.traversal.DefaultRemoteTraverser;
-import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
-import org.apache.tinkerpop.gremlin.python.jsr223.JythonScriptEngineSetup;
-import org.apache.tinkerpop.gremlin.structure.Edge;
-import org.apache.tinkerpop.gremlin.structure.Property;
-import org.apache.tinkerpop.gremlin.structure.Vertex;
-import org.apache.tinkerpop.gremlin.structure.VertexProperty;
-import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper;
-import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONVersion;
-import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerFactory;
-import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.python.jsr223.PyScriptEngine;
-
-import javax.script.ScriptContext;
-import javax.script.ScriptEngine;
-import javax.script.ScriptEngineManager;
-import java.math.BigInteger;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-/**
- * @author Marko A. Rodriguez (http://markorodriguez.com)
- */
-@Ignore
-public class GraphSONReaderTest {
-
-    private static final Set<GraphSONVersion> VERSIONS = new HashSet<>(Arrays.asList(GraphSONVersion.V2_0, GraphSONVersion.V3_0));
-    private static final GraphTraversalSource g = TinkerFactory.createModern().traversal();
-
-    @Test
-    public void shouldDeserializeGraphObjects() throws Exception {
-        for (final GraphSONVersion version : VERSIONS) {
-            final ScriptEngine jythonEngine = JythonScriptEngineSetup.setup((PyScriptEngine) new ScriptEngineManager().getEngineByName("jython"));
-            jythonEngine.eval("graphson_reader = " + (version.equals(GraphSONVersion.V2_0) ? "graphsonV2d0_reader" : "graphsonV3d0_reader"));
-            final ObjectMapper mapper = GraphSONMapper.build().version(version).create().createMapper();
-            //
-            final Vertex vertex = g.V(1).next();
-            jythonEngine.getBindings(ScriptContext.ENGINE_SCOPE).put("x", mapper.writeValueAsString(vertex));
-            assertEquals(vertex.toString(), jythonEngine.eval("str(graphson_reader.readObject(x))"));
-            assertTrue((Boolean) jythonEngine.eval("isinstance(graphson_reader.readObject(x),Vertex)"));
-            assertEquals("person", jythonEngine.eval("graphson_reader.readObject(x).label"));
-            assertEquals(1, jythonEngine.eval("graphson_reader.readObject(x).id"));
-            //
-            final Edge edge = g.V(1).outE("created").next();
-            jythonEngine.getBindings(ScriptContext.ENGINE_SCOPE).put("x", mapper.writeValueAsString(edge));
-            assertEquals(edge.toString(), jythonEngine.eval("str(graphson_reader.readObject(x))"));
-            assertTrue((Boolean) jythonEngine.eval("isinstance(graphson_reader.readObject(x),Edge)"));
-            assertEquals("created", jythonEngine.eval("graphson_reader.readObject(x).label"));
-            //
-            final VertexProperty vertexProperty = (VertexProperty) g.V(1).properties("name").next();
-            jythonEngine.getBindings(ScriptContext.ENGINE_SCOPE).put("x", mapper.writeValueAsString(vertexProperty));
-            assertEquals(vertexProperty.toString(), jythonEngine.eval("str(graphson_reader.readObject(x))"));
-            assertTrue((Boolean) jythonEngine.eval("isinstance(graphson_reader.readObject(x),VertexProperty)"));
-            //
-            final Property property = g.V(1).outE("created").properties("weight").next();
-            jythonEngine.getBindings(ScriptContext.ENGINE_SCOPE).put("x", mapper.writeValueAsString(property));
-            assertEquals(property.toString(), jythonEngine.eval("str(graphson_reader.readObject(x))"));
-            assertTrue((Boolean) jythonEngine.eval("isinstance(graphson_reader.readObject(x),Property)"));
-            //
-            final Traverser<Vertex> traverser = new DefaultRemoteTraverser<>(vertex, 3L);
-            jythonEngine.getBindings(ScriptContext.ENGINE_SCOPE).put("x", mapper.writeValueAsString(traverser));
-            assertEquals(traverser.toString(), jythonEngine.eval("str(graphson_reader.readObject(x))"));
-            assertEquals(BigInteger.valueOf(3L), jythonEngine.eval("graphson_reader.readObject(x).bulk")); // jython uses big integer in Java
-            assertTrue((Boolean) jythonEngine.eval("isinstance(graphson_reader.readObject(x).object,Vertex)"));
-            assertTrue((Boolean) jythonEngine.eval("isinstance(graphson_reader.readObject(x),Traverser)"));
-        }
-    }
-
-    @Test
-    public void shouldDeserializeNumbers() throws Exception {
-        for (final GraphSONVersion version : VERSIONS) {
-            final ScriptEngine jythonEngine = JythonScriptEngineSetup.setup((PyScriptEngine) new ScriptEngineManager().getEngineByName("jython"));
-            jythonEngine.eval("graphson_reader = " + (version.equals(GraphSONVersion.V2_0) ? "graphsonV2d0_reader" : "graphsonV3d0_reader"));
-            final ObjectMapper mapper = GraphSONMapper.build().version(version).create().createMapper();
-            //
-            jythonEngine.getBindings(ScriptContext.ENGINE_SCOPE).put("x", mapper.writeValueAsString(1));
-            assertEquals("1", jythonEngine.eval("str(graphson_reader.readObject(x))"));
-            assertTrue((Boolean) jythonEngine.eval("isinstance(graphson_reader.readObject(x),int)"));
-            //
-            jythonEngine.getBindings(ScriptContext.ENGINE_SCOPE).put("x", mapper.writeValueAsString(1L));
-            assertEquals("1", jythonEngine.eval("str(graphson_reader.readObject(x))"));
-            assertTrue((Boolean) jythonEngine.eval("isinstance(graphson_reader.readObject(x),long)"));
-            //
-            jythonEngine.getBindings(ScriptContext.ENGINE_SCOPE).put("x", mapper.writeValueAsString(1.2f));
-            assertEquals("1.2", jythonEngine.eval("str(graphson_reader.readObject(x))"));
-            assertTrue((Boolean) jythonEngine.eval("isinstance(graphson_reader.readObject(x),float)"));
-            //
-            jythonEngine.getBindings(ScriptContext.ENGINE_SCOPE).put("x", mapper.writeValueAsString(1.3d));
-            assertEquals("1.3", jythonEngine.eval("str(graphson_reader.readObject(x))"));
-            assertTrue((Boolean) jythonEngine.eval("isinstance(graphson_reader.readObject(x),float)"));
-        }
-    }
-
-    @Test
-    public void shouldDeserializeCollections() throws Exception {
-        for (final GraphSONVersion version : VERSIONS) {
-            final ScriptEngine jythonEngine = JythonScriptEngineSetup.setup((PyScriptEngine) new ScriptEngineManager().getEngineByName("jython"));
-            jythonEngine.eval("graphson_reader = " + (version.equals(GraphSONVersion.V2_0) ? "graphsonV2d0_reader" : "graphsonV3d0_reader"));
-            final ObjectMapper mapper = GraphSONMapper.build().version(version).create().createMapper();
-            //
-            final Map<String, Number> map = new LinkedHashMap<>();
-            map.put("a", 2);
-            map.put("b", 2.3d);
-            jythonEngine.getBindings(ScriptContext.ENGINE_SCOPE).put("x", mapper.writeValueAsString(map));
-            assertEquals("{u'a': 2, u'b': 2.3}", jythonEngine.eval("str(graphson_reader.readObject(x))"));
-            assertEquals(2, jythonEngine.eval("graphson_reader.readObject(x)['a']"));
-            assertEquals(2.3d, jythonEngine.eval("graphson_reader.readObject(x)['b']")); // jython is smart about double
-            assertTrue((Boolean) jythonEngine.eval("isinstance(graphson_reader.readObject(x)['a'],int)"));
-            assertTrue((Boolean) jythonEngine.eval("isinstance(graphson_reader.readObject(x)['b'],float)"));
-            //
-            final List<Object> list = Arrays.asList(g.V(1).next(), "hello", map, true);
-            jythonEngine.getBindings(ScriptContext.ENGINE_SCOPE).put("x", mapper.writeValueAsString(list));
-            assertEquals("[v[1], u'hello', {u'a': 2, u'b': 2.3}, True]", jythonEngine.eval("str(graphson_reader.readObject(x))"));
-            assertEquals(g.V(1).next().toString(), jythonEngine.eval("str(graphson_reader.readObject(x)[0])"));
-            assertEquals("hello", jythonEngine.eval("graphson_reader.readObject(x)[1]"));
-            assertEquals("{u'a': 2, u'b': 2.3}", jythonEngine.eval("str(graphson_reader.readObject(x)[2])"));
-            assertTrue((Boolean) jythonEngine.eval("graphson_reader.readObject(x)[3]"));
-            assertTrue((Boolean) jythonEngine.eval("isinstance(graphson_reader.readObject(x)[0],Vertex)"));
-            // assertTrue((Boolean) jythonEngine.eval("isinstance(graphson_reader.readObject(x)[1],str)")); // its python unicode jython object
-            assertTrue((Boolean) jythonEngine.eval("isinstance(graphson_reader.readObject(x)[2],dict)"));
-            assertTrue((Boolean) jythonEngine.eval("isinstance(graphson_reader.readObject(x)[3],bool)"));
-        }
-    }
-}
diff --git a/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/structure/io/graphson/GraphSONWriterTest.java b/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/structure/io/graphson/GraphSONWriterTest.java
deleted file mode 100644
index 905d9c7..0000000
--- a/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/structure/io/graphson/GraphSONWriterTest.java
+++ /dev/null
@@ -1,163 +0,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.
- */
-
-package org.apache.tinkerpop.gremlin.python.structure.io.graphson;
-
-import org.apache.tinkerpop.gremlin.process.remote.traversal.DefaultRemoteTraverser;
-import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
-import org.apache.tinkerpop.gremlin.process.traversal.P;
-import org.apache.tinkerpop.gremlin.process.traversal.Pop;
-import org.apache.tinkerpop.gremlin.process.traversal.Scope;
-import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
-import org.apache.tinkerpop.gremlin.process.traversal.util.AndP;
-import org.apache.tinkerpop.gremlin.python.jsr223.JythonScriptEngineSetup;
-import org.apache.tinkerpop.gremlin.structure.Column;
-import org.apache.tinkerpop.gremlin.structure.T;
-import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper;
-import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONVersion;
-import org.apache.tinkerpop.gremlin.util.function.Lambda;
-import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.python.jsr223.PyScriptEngine;
-
-import javax.script.ScriptEngine;
-import javax.script.ScriptEngineManager;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-/**
- * @author Marko A. Rodriguez (http://markorodriguez.com)
- */
-@Ignore
-public class GraphSONWriterTest {
-
-    private static final Set<GraphSONVersion> VERSIONS = new HashSet<>(Arrays.asList(GraphSONVersion.V2_0, GraphSONVersion.V3_0));
-
-    @Test
-    public void shouldSerializeNumbers() throws Exception {
-        for (final GraphSONVersion version : VERSIONS) {
-            final ScriptEngine jythonEngine = JythonScriptEngineSetup.setup((PyScriptEngine) new ScriptEngineManager().getEngineByName("jython"));
-            jythonEngine.eval("graphson_writer = " + (version.equals(GraphSONVersion.V2_0) ? "graphsonV2d0_writer" : "graphsonV3d0_writer"));
-            final ObjectMapper mapper = GraphSONMapper.build().version(version).create().createMapper();
-            //
-            assertEquals(1, mapper.readValue(jythonEngine.eval("graphson_writer.writeObject(1)").toString(), Object.class));
-            assertEquals(mapper.writeValueAsString(1), jythonEngine.eval("graphson_writer.writeObject(1)").toString().replace(" ", ""));
-            //
-            assertEquals(2L, mapper.readValue(jythonEngine.eval("graphson_writer.writeObject(2L)").toString(), Object.class));
-            assertEquals(mapper.writeValueAsString(2L), jythonEngine.eval("graphson_writer.writeObject(2L)").toString().replace(" ", ""));
-            //
-            assertEquals(3.4, mapper.readValue(jythonEngine.eval("graphson_writer.writeObject(3.4)").toString(), Object.class));
-            assertEquals(mapper.writeValueAsString(3.4), jythonEngine.eval("graphson_writer.writeObject(3.4)").toString().replace(" ", ""));
-        }
-    }
-
-    @Test
-    public void shouldSerializeCollections() throws Exception {
-        for (final GraphSONVersion version : VERSIONS) {
-            final ScriptEngine jythonEngine = JythonScriptEngineSetup.setup((PyScriptEngine) new ScriptEngineManager().getEngineByName("jython"));
-            jythonEngine.eval("graphson_writer = " + (version.equals(GraphSONVersion.V2_0) ? "graphsonV2d0_writer" : "graphsonV3d0_writer"));
-            final ObjectMapper mapper = GraphSONMapper.build().version(version).create().createMapper();
-            //
-            final Map<String, Number> map = new LinkedHashMap<>();
-            map.put("a", 2);
-            map.put("b", 2.3);
-            assertEquals(map, mapper.readValue(jythonEngine.eval("graphson_writer.writeObject({'a':2,'b':2.3})").toString(), Object.class));
-            //
-            final List<Object> list = Arrays.asList(new DefaultRemoteTraverser<>("hello", 3L), "hello", map, true);
-            assertTrue((Boolean) jythonEngine.eval("isinstance([Traverser('hello',3L),'hello',{'a':2,'b':2.3},True],list)"));
-            assertEquals(list, mapper.readValue(jythonEngine.eval("graphson_writer.writeObject([Traverser('hello',3L),'hello',{'a':2,'b':2.3},True])").toString(), Object.class));
-        }
-    }
-
-    @Test
-    public void shouldSerializeTraverser() throws Exception {
-        for (final GraphSONVersion version : VERSIONS) {
-            final ScriptEngine jythonEngine = JythonScriptEngineSetup.setup((PyScriptEngine) new ScriptEngineManager().getEngineByName("jython"));
-            jythonEngine.eval("graphson_writer = " + (version.equals(GraphSONVersion.V2_0) ? "graphsonV2d0_writer" : "graphsonV3d0_writer"));
-            final ObjectMapper mapper = GraphSONMapper.build().version(version).create().createMapper();
-            //
-            assertEquals(
-                    new DefaultRemoteTraverser<>("hello", 3L),
-                    mapper.readValue(jythonEngine.eval("graphson_writer.writeObject(Traverser('hello',3L))").toString(), Object.class));
-            assertEquals(3L, mapper.readValue(jythonEngine.eval("graphson_writer.writeObject(Traverser('hello',3L))").toString(), Traverser.class).bulk());
-            assertEquals("hello", mapper.readValue(jythonEngine.eval("graphson_writer.writeObject(Traverser('hello',3L))").toString(), Traverser.class).get());
-        }
-    }
-
-    @Test
-    public void shouldSerializeBytecode() throws Exception {
-        for (final GraphSONVersion version : VERSIONS) {
-            final ScriptEngine jythonEngine = JythonScriptEngineSetup.setup((PyScriptEngine) new ScriptEngineManager().getEngineByName("jython"));
-            jythonEngine.eval("graphson_writer = " + (version.equals(GraphSONVersion.V2_0) ? "graphsonV2d0_writer" : "graphsonV3d0_writer"));
-            final ObjectMapper mapper = GraphSONMapper.build().version(version).create().createMapper();
-            //
-            assertEquals(P.eq(7L), mapper.readValue(jythonEngine.eval("graphson_writer.writeObject(P.eq(7L))").toString(), Object.class));
-            // TODO: assertEquals(mapper.writeValueAsString(P.between(1, 2).and(P.eq(7L))), jythonEngine.eval("graphson_writer.writeObject(P.eq(7L)._and(P.between(1,2)))").toString().replace(" ",""));
-            assertEquals(AndP.class, mapper.readValue(jythonEngine.eval("graphson_writer.writeObject(P.eq(7L).and_(P.between(1,2)))").toString(), Object.class).getClass());
-            //
-            assertEquals(new Bytecode.Binding<>("a", 5L), mapper.readValue(jythonEngine.eval("graphson_writer.writeObject(Binding('a',5L))").toString(), Object.class));
-            //
-            for (final Column t : Column.values()) {
-                assertEquals(t, mapper.readValue(jythonEngine.eval("graphson_writer.writeObject(Column." + t.name() + ")").toString(), Object.class));
-            }
-            for (final T t : T.values()) {
-                assertEquals(t, mapper.readValue(jythonEngine.eval("graphson_writer.writeObject(T." + t.name() + ")").toString(), Object.class));
-            }
-            assertEquals(Pop.first, mapper.readValue(jythonEngine.eval("graphson_writer.writeObject(Pop.first)").toString(), Object.class));
-            assertEquals(Pop.last, mapper.readValue(jythonEngine.eval("graphson_writer.writeObject(Pop.last)").toString(), Object.class));
-            assertEquals(Pop.all, mapper.readValue(jythonEngine.eval("graphson_writer.writeObject(Pop.all_)").toString(), Object.class));
-            assertEquals(Pop.mixed, mapper.readValue(jythonEngine.eval("graphson_writer.writeObject(Pop.mixed)").toString(), Object.class));
-            assertEquals(Scope.global, mapper.readValue(jythonEngine.eval("graphson_writer.writeObject(Scope.global_)").toString(), Object.class));
-            assertEquals(Scope.local, mapper.readValue(jythonEngine.eval("graphson_writer.writeObject(Scope.local)").toString(), Object.class));
-        }
-    }
-
-    @Test
-    public void shouldSerializeLambda() throws Exception {
-        for (final GraphSONVersion version : VERSIONS) {
-            final ScriptEngine jythonEngine = JythonScriptEngineSetup.setup((PyScriptEngine) new ScriptEngineManager().getEngineByName("jython"));
-            jythonEngine.eval("graphson_writer = " + (version.equals(GraphSONVersion.V2_0) ? "graphsonV2d0_writer" : "graphsonV3d0_writer"));
-            final ObjectMapper mapper = GraphSONMapper.build().version(version).create().createMapper();
-            //
-            assertEquals(
-                    Lambda.function("lambda z : 1+2", "gremlin-python"),
-                    mapper.readValue(jythonEngine.eval("graphson_writer.writeObject(lambda : 'z : 1+2')").toString(), Object.class));
-            assertEquals(
-                    Lambda.function("lambda z : z+ 7", "gremlin-python"),
-                    mapper.readValue(jythonEngine.eval("graphson_writer.writeObject(lambda : 'lambda z : z+ 7')").toString(), Object.class));
-            assertEquals(
-                    Lambda.supplier("lambda : 23", "gremlin-python"),
-                    mapper.readValue(jythonEngine.eval("graphson_writer.writeObject(lambda : 'lambda : 23')").toString(), Object.class));
-            assertEquals(
-                    Lambda.consumer("lambda z : z + 23", "gremlin-python"),
-                    mapper.readValue(jythonEngine.eval("graphson_writer.writeObject(lambda : 'lambda z : z + 23')").toString(), Object.class));
-            assertEquals(
-                    Lambda.biFunction("lambda z,y : z - y + 2", "gremlin-python"),
-                    mapper.readValue(jythonEngine.eval("graphson_writer.writeObject(lambda : 'lambda z,y : z - y + 2')").toString(), Object.class));
-        }
-    }
-}
diff --git a/gremlin-python/src/test/resources/log4j-silent.properties b/gremlin-python/src/test/resources/log4j-silent.properties
deleted file mode 100644
index 1825bb0..0000000
--- a/gremlin-python/src/test/resources/log4j-silent.properties
+++ /dev/null
@@ -1,23 +0,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.
-
-# this file should always have logging set to OFF.  it seems, however, that an appender of some sort is
-# required or else some logs throw error and use other log4j.properties files on the path.
-log4j.rootLogger=OFF, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n
\ No newline at end of file
diff --git a/gremlin-python/src/test/resources/log4j-test.properties b/gremlin-python/src/test/resources/log4j-test.properties
deleted file mode 100644
index 79038b1..0000000
--- a/gremlin-python/src/test/resources/log4j-test.properties
+++ /dev/null
@@ -1,23 +0,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.
-#
-
-log4j.rootLogger=WARN, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n
\ No newline at end of file
diff --git a/gremlin-server/Dockerfile b/gremlin-server/Dockerfile
index 3b1e849..fe8126a 100644
--- a/gremlin-server/Dockerfile
+++ b/gremlin-server/Dockerfile
@@ -15,7 +15,7 @@
 # specific language governing permissions and limitations
 # under the License.
 
-FROM openjdk:8-jre-alpine
+FROM adoptopenjdk/openjdk11:alpine-slim
 
 LABEL maintainer="dev@tinkerpop.apache.org"
 
diff --git a/gremlin-server/conf/gremlin-server-classic.yaml b/gremlin-server/conf/gremlin-server-classic.yaml
index 248a6bf..15b2397 100644
--- a/gremlin-server/conf/gremlin-server-classic.yaml
+++ b/gremlin-server/conf/gremlin-server-classic.yaml
@@ -27,8 +27,6 @@
                org.apache.tinkerpop.gremlin.jsr223.ImportGremlinPlugin: {classImports: [java.lang.Math], methodImports: [java.lang.Math#*]},
                org.apache.tinkerpop.gremlin.jsr223.ScriptFileGremlinPlugin: {files: [scripts/generate-classic.groovy]}}}}
 serializers:
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3d0] }}            # application/vnd.gremlin-v3.0+gryo
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0, config: { serializeResultToString: true }}                                                                      # application/vnd.gremlin-v3.0+gryo-stringd
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV3d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3d0] }}        # application/json
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1 }                                                                                                           # application/vnd.graphbinary-v1.0
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1, config: { serializeResultToString: true }}                                                                 # application/vnd.graphbinary-v1.0-stringd
diff --git a/gremlin-server/conf/gremlin-server-modern-py.yaml b/gremlin-server/conf/gremlin-server-modern-py.yaml
deleted file mode 100644
index 3193d5f..0000000
--- a/gremlin-server/conf/gremlin-server-modern-py.yaml
+++ /dev/null
@@ -1,61 +0,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.
-
-# Note that TinkerPop does not include gremlin-python dependencies in
-# its distributions. This file cannot be used as a configuration file
-# to Gremlin Server unless those dependencies are installed on the
-# Gremlin Server path with:
-#
-# bin/gremlin-server.sh -i org.apache.tinkerpop gremlin-python x.y.z
-#
-# The primary change in this file to enable the GremlinJythonScriptEngine
-# is the addition of "gremlin-jython" to the "scriptEngines" field.
-
-host: localhost
-port: 8182
-threadPoolWorker: 1
-gremlinPool: 8
-evaluationTimeout: 30000
-graphs: {
-  graph: conf/tinkergraph-empty.properties}
-scriptEngines: {
-  gremlin-groovy: {
-    plugins: { org.apache.tinkerpop.gremlin.server.jsr223.GremlinServerGremlinPlugin: {},
-               org.apache.tinkerpop.gremlin.tinkergraph.jsr223.TinkerGraphGremlinPlugin: {},
-               org.apache.tinkerpop.gremlin.jsr223.ImportGremlinPlugin: {classImports: [java.lang.Math], methodImports: [java.lang.Math#*]},
-               org.apache.tinkerpop.gremlin.jsr223.ScriptFileGremlinPlugin: {files: [scripts/generate-modern.groovy]}}},
-  gremlin-jython: {},
-  gremlin-python: {}
-}
-serializers:
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3d0] }}            # application/vnd.gremlin-v3.0+gryo
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0, config: { serializeResultToString: true }}                                                                      # application/vnd.gremlin-v3.0+gryo-stringd
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV3d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3d0] }}        # application/json
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1 }                                                                                                           # application/vnd.graphbinary-v1.0
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1, config: { serializeResultToString: true }}                                                                 # application/vnd.graphbinary-v1.0-stringd
-metrics: {
-  slf4jReporter: {enabled: true, interval: 180000}}
-strictTransactionManagement: false
-idleConnectionTimeout: 0
-keepAliveInterval: 0
-threadPoolBoss: 1
-maxInitialLineLength: 4096
-maxHeaderSize: 8192
-maxChunkSize: 8192
-maxContentLength: 65536
-maxAccumulationBufferComponents: 1024
-resultIterationBatchSize: 64
diff --git a/gremlin-server/conf/gremlin-server-modern-readonly.yaml b/gremlin-server/conf/gremlin-server-modern-readonly.yaml
index 7388f73..705163f 100644
--- a/gremlin-server/conf/gremlin-server-modern-readonly.yaml
+++ b/gremlin-server/conf/gremlin-server-modern-readonly.yaml
@@ -27,8 +27,6 @@
                org.apache.tinkerpop.gremlin.jsr223.ImportGremlinPlugin: {classImports: [java.lang.Math], methodImports: [java.lang.Math#*]},
                org.apache.tinkerpop.gremlin.jsr223.ScriptFileGremlinPlugin: {files: [scripts/generate-modern-readonly.groovy]}}}}
 serializers:
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3d0] }}            # application/vnd.gremlin-v3.0+gryo
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0, config: { serializeResultToString: true }}                                                                      # application/vnd.gremlin-v3.0+gryo-stringd
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV3d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3d0] }}        # application/json
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1 }                                                                                                           # application/vnd.graphbinary-v1.0
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1, config: { serializeResultToString: true }}                                                                 # application/vnd.graphbinary-v1.0-stringd
diff --git a/gremlin-server/conf/gremlin-server-modern.yaml b/gremlin-server/conf/gremlin-server-modern.yaml
index 5f83508..e9ace56 100644
--- a/gremlin-server/conf/gremlin-server-modern.yaml
+++ b/gremlin-server/conf/gremlin-server-modern.yaml
@@ -28,8 +28,6 @@
                org.apache.tinkerpop.gremlin.jsr223.ImportGremlinPlugin: {classImports: [java.lang.Math], methodImports: [java.lang.Math#*]},
                org.apache.tinkerpop.gremlin.jsr223.ScriptFileGremlinPlugin: {files: [scripts/generate-modern.groovy]}}}}
 serializers:
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3d0] }}            # application/vnd.gremlin-v3.0+gryo
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0, config: { serializeResultToString: true }}                                                                      # application/vnd.gremlin-v3.0+gryo-stringd
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV3d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3d0] }}        # application/json
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1 }                                                                                                           # application/vnd.graphbinary-v1.0
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1, config: { serializeResultToString: true }}                                                                 # application/vnd.graphbinary-v1.0-stringd
diff --git a/gremlin-server/conf/gremlin-server-neo4j.yaml b/gremlin-server/conf/gremlin-server-neo4j.yaml
index 08e42a8..6f838af 100644
--- a/gremlin-server/conf/gremlin-server-neo4j.yaml
+++ b/gremlin-server/conf/gremlin-server-neo4j.yaml
@@ -38,8 +38,6 @@
                org.apache.tinkerpop.gremlin.jsr223.ImportGremlinPlugin: {classImports: [java.lang.Math], methodImports: [java.lang.Math#*]},
                org.apache.tinkerpop.gremlin.jsr223.ScriptFileGremlinPlugin: {files: [scripts/empty-sample.groovy]}}}}
 serializers:
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3d0] }}            # application/vnd.gremlin-v3.0+gryo
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0, config: { serializeResultToString: true }}                                                                      # application/vnd.gremlin-v3.0+gryo-stringd
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV3d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3d0] }}        # application/json
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1 }                                                                                                           # application/vnd.graphbinary-v1.0
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1, config: { serializeResultToString: true }}                                                                 # application/vnd.graphbinary-v1.0-stringd
diff --git a/gremlin-server/conf/gremlin-server-secure.yaml b/gremlin-server/conf/gremlin-server-secure.yaml
index dec2bb3..93c4323 100644
--- a/gremlin-server/conf/gremlin-server-secure.yaml
+++ b/gremlin-server/conf/gremlin-server-secure.yaml
@@ -37,8 +37,6 @@
                org.apache.tinkerpop.gremlin.jsr223.ImportGremlinPlugin: {classImports: [java.lang.Math], methodImports: [java.lang.Math#*]},
                org.apache.tinkerpop.gremlin.jsr223.ScriptFileGremlinPlugin: {files: [scripts/empty-sample-secure.groovy]}}}}
 serializers:
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3d0] }}            # application/vnd.gremlin-v3.0+gryo
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0, config: { serializeResultToString: true }}                                                                      # application/vnd.gremlin-v3.0+gryo-stringd
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV3d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3d0] }}        # application/json
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1 }                                                                                                           # application/vnd.graphbinary-v1.0
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1, config: { serializeResultToString: true }}                                                                 # application/vnd.graphbinary-v1.0-stringd
diff --git a/gremlin-server/conf/gremlin-server-spark.yaml b/gremlin-server/conf/gremlin-server-spark.yaml
index 4d974bf..8634eab 100644
--- a/gremlin-server/conf/gremlin-server-spark.yaml
+++ b/gremlin-server/conf/gremlin-server-spark.yaml
@@ -51,8 +51,6 @@
                org.apache.tinkerpop.gremlin.jsr223.ImportGremlinPlugin: {classImports: [java.lang.Math], methodImports: [java.lang.Math#*]},
                org.apache.tinkerpop.gremlin.jsr223.ScriptFileGremlinPlugin: {files: [scripts/spark.groovy]}}}}
 serializers:
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3d0] }}            # application/vnd.gremlin-v3.0+gryo
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0, config: { serializeResultToString: true }}                                                                      # application/vnd.gremlin-v3.0+gryo-stringd
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV3d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3d0] }}        # application/json
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1 }                                                                                                           # application/vnd.graphbinary-v1.0
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1, config: { serializeResultToString: true }}                                                                 # application/vnd.graphbinary-v1.0-stringd
diff --git a/gremlin-server/conf/gremlin-server.yaml b/gremlin-server/conf/gremlin-server.yaml
index 86f4e92..4f210c8 100644
--- a/gremlin-server/conf/gremlin-server.yaml
+++ b/gremlin-server/conf/gremlin-server.yaml
@@ -28,8 +28,6 @@
                org.apache.tinkerpop.gremlin.jsr223.ImportGremlinPlugin: {classImports: [java.lang.Math], methodImports: [java.lang.Math#*]},
                org.apache.tinkerpop.gremlin.jsr223.ScriptFileGremlinPlugin: {files: [scripts/empty-sample.groovy]}}}}
 serializers:
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3d0] }}            # application/vnd.gremlin-v3.0+gryo
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0, config: { serializeResultToString: true }}                                                                      # application/vnd.gremlin-v3.0+gryo-stringd
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV3d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3d0] }}        # application/json
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1 }                                                                                                           # application/vnd.graphbinary-v1.0
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1, config: { serializeResultToString: true }}                                                                 # application/vnd.graphbinary-v1.0-stringd
diff --git a/gremlin-server/data/README.asciidoc b/gremlin-server/data/README.asciidoc
new file mode 100644
index 0000000..d2787f8
--- /dev/null
+++ b/gremlin-server/data/README.asciidoc
@@ -0,0 +1,26 @@
+////
+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.
+////
+This directory contains data files that are packaged with Gremlin Server:
+
+* `credentials.kryo` - This data file contains a sample graph built from the
+link:https://tinkerpop.apache.org/docs/current/reference/#credentials-dsl[Credentials DSL] which contains two
+users: `stephen/password` and `marko/rainbow-dash`. This file is meant to be used by the `gremlin-server-secure.yaml`
+and `gremlin-server-rest-secure.yaml` configuration files to demonstrate basic authentication functions.
+* `sample.kryo` - This data file contains a random sample graph generated from the `DistributionGenerator` in
+`IoDataGenerateTest.shouldWriteSampleForGremlinServer()`. It can be configured for use in Gremlin Server by using the
+`load-sample.groovy` server initialization script file packaged with Gremlin Server. This graph has 10,000 vertices
+and approximately 100,000 edges (using a "knows" label).
diff --git a/gremlin-server/data/credentials.kryo b/gremlin-server/data/credentials.kryo
index 163d2ef..2a2d6ae 100644
--- a/gremlin-server/data/credentials.kryo
+++ b/gremlin-server/data/credentials.kryo
Binary files differ
diff --git a/gremlin-server/pom.xml b/gremlin-server/pom.xml
index 6eed13c..b36461b 100644
--- a/gremlin-server/pom.xml
+++ b/gremlin-server/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.apache.tinkerpop</groupId>
         <artifactId>tinkerpop</artifactId>
-        <version>3.4.12-SNAPSHOT</version>
+        <version>3.5.1-SNAPSHOT</version>
     </parent>
     <artifactId>gremlin-server</artifactId>
     <name>Apache TinkerPop :: Gremlin Server</name>
@@ -100,12 +100,6 @@
             <version>${project.version}</version>
             <scope>test</scope>
         </dependency>
-        <dependency>
-            <groupId>org.apache.kerby</groupId>
-            <artifactId>kerb-simplekdc</artifactId>
-            <version>2.0.0</version>
-            <scope>test</scope>
-        </dependency>
     </dependencies>
     <build>
         <directory>${basedir}/target</directory>
@@ -156,7 +150,6 @@
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-surefire-plugin</artifactId>
             </plugin>
-
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-failsafe-plugin</artifactId>
@@ -206,28 +199,52 @@
                 <dependency>
                     <groupId>org.neo4j</groupId>
                     <artifactId>neo4j-tinkerpop-api-impl</artifactId>
-                    <version>0.3-2.3.3</version>
+                    <version>0.9-3.4.0</version>
                     <scope>test</scope>
                     <exclusions>
                         <exclusion>
+                            <groupId>org.neo4j</groupId>
+                            <artifactId>neo4j-kernel</artifactId>
+                        </exclusion>
+                        <exclusion>
                             <groupId>org.apache.commons</groupId>
                             <artifactId>commons-lang3</artifactId>
                         </exclusion>
                         <exclusion>
-                            <groupId>com.googlecode.concurrentlinkedhashmap</groupId>
-                            <artifactId>concurrentlinkedhashmap-lru</artifactId>
+                            <groupId>org.apache.commons</groupId>
+                            <artifactId>commons-text</artifactId>
+                        </exclusion>
+                        <exclusion>
+                            <groupId>com.github.ben-manes.caffeine</groupId>
+                            <artifactId>caffeine</artifactId>
                         </exclusion>
                         <exclusion>
                             <groupId>org.scala-lang</groupId>
                             <artifactId>scala-library</artifactId>
                         </exclusion>
                         <exclusion>
+                            <groupId>org.scala-lang</groupId>
+                            <artifactId>scala-reflect</artifactId>
+                        </exclusion>
+                        <exclusion>
                             <groupId>org.slf4j</groupId>
                             <artifactId>slf4j-api</artifactId>
                         </exclusion>
                         <exclusion>
-                            <groupId>info.ganglia.gmetric4j</groupId>
-                            <artifactId>gmetric4j</artifactId>
+                            <groupId>org.slf4j</groupId>
+                            <artifactId>slf4j-nop</artifactId>
+                        </exclusion>
+                        <exclusion>
+                            <groupId>org.apache.lucene</groupId>
+                            <artifactId>lucene-core</artifactId>
+                        </exclusion>
+                        <exclusion>
+                            <groupId>io.dropwizard.metrics</groupId>
+                            <artifactId>metrics-core</artifactId>
+                        </exclusion>
+                        <exclusion>
+                            <groupId>io.netty</groupId>
+                            <artifactId>netty-all</artifactId>
                         </exclusion>
                         <exclusion>
                             <groupId>org.ow2.asm</groupId>
@@ -235,6 +252,42 @@
                         </exclusion>
                     </exclusions>
                 </dependency>
+                <dependency>
+                    <groupId>org.scala-lang</groupId>
+                    <artifactId>scala-library</artifactId>
+                    <version>2.11.8</version>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>org.scala-lang</groupId>
+                    <artifactId>scala-reflect</artifactId>
+                    <version>2.11.8</version>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>org.apache.lucene</groupId>
+                    <artifactId>lucene-core</artifactId>
+                    <version>5.5.0</version>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>io.dropwizard.metrics</groupId>
+                    <artifactId>metrics-core</artifactId>
+                    <version>4.0.2</version>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>org.neo4j</groupId>
+                    <artifactId>neo4j-kernel</artifactId>
+                    <version>3.4.11</version>
+                    <scope>test</scope>
+                    <exclusions>
+                        <exclusion>
+                            <groupId>io.netty</groupId>
+                            <artifactId>netty-all</artifactId>
+                        </exclusion>
+                    </exclusions>
+                </dependency>
                 <!-- *** WARNING *** -->
             </dependencies>
             <build>
@@ -344,7 +397,7 @@
                             <repository>tinkerpop/gremlin-server</repository>
                         </configuration>
                     </plugin>
-                </plugins>                
+                </plugins>
             </build>
         </profile>
     </profiles>
diff --git a/gremlin-server/src/assembly/standalone.xml b/gremlin-server/src/assembly/standalone.xml
index f804623..e884267 100644
--- a/gremlin-server/src/assembly/standalone.xml
+++ b/gremlin-server/src/assembly/standalone.xml
@@ -57,6 +57,9 @@
         <fileSet>
             <directory>data</directory>
             <outputDirectory>/data</outputDirectory>
+            <excludes>
+                <exclude>README.asciidoc</exclude>
+            </excludes>
         </fileSet>
         <fileSet>
             <directory>../data</directory>
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/AbstractChannelizer.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/AbstractChannelizer.java
index e3da46a..ee02bd8 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/AbstractChannelizer.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/AbstractChannelizer.java
@@ -26,20 +26,19 @@
 import org.apache.tinkerpop.gremlin.driver.MessageSerializer;
 import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
-import org.apache.tinkerpop.gremlin.driver.ser.AbstractGryoMessageSerializerV1d0;
 import org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1;
 import org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV2d0;
-import org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0;
 import org.apache.tinkerpop.gremlin.groovy.engine.GremlinExecutor;
 import org.apache.tinkerpop.gremlin.server.auth.Authenticator;
+import org.apache.tinkerpop.gremlin.server.authz.Authorizer;
 import org.apache.tinkerpop.gremlin.server.handler.AbstractAuthenticationHandler;
 import org.apache.tinkerpop.gremlin.server.handler.OpExecutorHandler;
 import org.apache.tinkerpop.gremlin.server.handler.OpSelectorHandler;
+import org.apache.tinkerpop.gremlin.server.util.ServerGremlinExecutor;
 import org.apache.tinkerpop.gremlin.structure.Graph;
 import io.netty.channel.ChannelInitializer;
 import io.netty.channel.ChannelPipeline;
 import io.netty.channel.socket.SocketChannel;
-import org.apache.tinkerpop.gremlin.server.util.ServerGremlinExecutor;
 import org.javatuples.Pair;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -48,10 +47,10 @@
 import javax.net.ssl.SSLException;
 import javax.net.ssl.TrustManagerFactory;
 
-import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.lang.reflect.Constructor;
 import java.security.KeyStore;
 import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
@@ -81,10 +80,6 @@
 public abstract class AbstractChannelizer extends ChannelInitializer<SocketChannel> implements Channelizer {
     private static final Logger logger = LoggerFactory.getLogger(AbstractChannelizer.class);
     protected static final List<Settings.SerializerSettings> DEFAULT_SERIALIZERS = Arrays.asList(
-            new Settings.SerializerSettings(GryoMessageSerializerV3d0.class.getName(), Collections.emptyMap()),
-            new Settings.SerializerSettings(GryoMessageSerializerV3d0.class.getName(), new HashMap<String,Object>(){{
-                put(AbstractGryoMessageSerializerV1d0.TOKEN_SERIALIZE_RESULT_TO_STRING, true);
-            }}),
             new Settings.SerializerSettings(GraphSONMessageSerializerV2d0.class.getName(), Collections.emptyMap()),
             new Settings.SerializerSettings(GraphBinaryMessageSerializerV1.class.getName(), Collections.emptyMap()),
             new Settings.SerializerSettings(GraphBinaryMessageSerializerV1.class.getName(), new HashMap<String,Object>(){{
@@ -101,8 +96,10 @@
 
 
     public static final String PIPELINE_AUTHENTICATOR = "authenticator";
+    public static final String PIPELINE_AUTHORIZER = "authorizer";
     public static final String PIPELINE_REQUEST_HANDLER = "request-handler";
     public static final String PIPELINE_HTTP_RESPONSE_ENCODER = "http-response-encoder";
+    public static final String PIPELINE_HTTP_AGGREGATOR = "http-aggregator";
     public static final String PIPELINE_WEBSOCKET_SERVER_COMPRESSION = "web-socket-server-compression-handler";
 
     protected static final String PIPELINE_SSL = "ssl";
@@ -112,15 +109,16 @@
 
     protected static final String GREMLIN_ENDPOINT = "/gremlin";
 
-    protected final Map<String, MessageSerializer> serializers = new HashMap<>();
+    protected final Map<String, MessageSerializer<?>> serializers = new HashMap<>();
 
     private OpSelectorHandler opSelectorHandler;
     private OpExecutorHandler opExecutorHandler;
 
     protected Authenticator authenticator;
+    protected Authorizer authorizer;
 
     /**
-     * This method is called from within {@code SocketChannel} just after the SSL handler is put in the pipeline.
+     * This method is called from within {@link #initChannel(SocketChannel)} just after the SSL handler is put in the pipeline.
      * Modify the pipeline as needed here.
      */
     public abstract void configure(final ChannelPipeline pipeline);
@@ -151,6 +149,7 @@
         if (sslContext.isPresent()) logger.info("SSL enabled");
 
         authenticator = createAuthenticator(settings.authentication);
+        authorizer = createAuthorizer(settings.authorization);
 
         // these handlers don't share any state and can thus be initialized once per pipeline
         opSelectorHandler = new OpSelectorHandler(settings, graphManager, gremlinExecutor, scheduledExecutorService, this);
@@ -182,16 +181,35 @@
         finalize(pipeline);
     }
 
-    protected AbstractAuthenticationHandler createAuthenticationHandler(final Settings.AuthenticationSettings config) {
+    protected AbstractAuthenticationHandler createAuthenticationHandler(final Settings settings) {
         try {
-            final Class<?> clazz = Class.forName(config.authenticationHandler);
-            final Class[] constructorArgs = new Class[2];
-            constructorArgs[0] = Authenticator.class;
-            constructorArgs[1] = Settings.AuthenticationSettings.class;
-            return (AbstractAuthenticationHandler) clazz.getDeclaredConstructor(constructorArgs).newInstance(authenticator, config);
+            final Class<?> clazz = Class.forName(settings.authentication.authenticationHandler);
+            AbstractAuthenticationHandler aah;
+            try {
+                // the three arg constructor is the new form as a handler may need the authorizer in some cases
+                final Class<?>[] threeArgForm = new Class[]{Authenticator.class, Authorizer.class, Settings.class};
+                final Constructor<?> twoArgConstructor = clazz.getDeclaredConstructor(threeArgForm);
+                return (AbstractAuthenticationHandler) twoArgConstructor.newInstance(authenticator, authorizer, settings);
+            } catch (Exception threeArgEx) {
+                try {
+                    // the two arg constructor is the "old form" that existed prior to Authorizers. should probably
+                    // deprecate this form
+                    final Class<?>[] twoArgForm = new Class[]{Authenticator.class, Settings.class};
+                    final Constructor<?> twoArgConstructor = clazz.getDeclaredConstructor(twoArgForm);
+
+                    if (authorizer != null) {
+                        logger.warn("There is an authorizer configured but the {} does not have a constructor of ({}, {}, {}) so it cannot be added",
+                                clazz.getName(), Authenticator.class.getSimpleName(), Authorizer.class.getSimpleName(), Settings.class.getSimpleName());
+                    }
+
+                    return (AbstractAuthenticationHandler) twoArgConstructor.newInstance(authenticator, settings);
+                } catch (Exception twoArgEx) {
+                    throw twoArgEx;
+                }
+            }
         } catch (Exception ex) {
             logger.warn(ex.getMessage());
-            throw new IllegalStateException(String.format("Could not create/configure AuthenticationHandler %s", config.authenticationHandler), ex);
+            throw new IllegalStateException(String.format("Could not create/configure AuthenticationHandler %s", settings.authentication.authenticationHandler), ex);
         }
     }
 
@@ -208,6 +226,22 @@
         }
     }
 
+    private Authorizer createAuthorizer(final Settings.AuthorizationSettings config) {
+        final String authorizerClass = config.authorizer;
+        if (null == authorizerClass) {
+            return null;
+        }
+        try {
+            final Class<?> clazz = Class.forName(authorizerClass);
+            final Authorizer authorizer = (Authorizer) clazz.newInstance();
+            authorizer.setup(config.config);
+            return authorizer;
+        } catch (Exception ex) {
+            logger.warn(ex.getMessage());
+            throw new IllegalStateException(String.format("Could not create/configure Authorizer %s", authorizer), ex);
+        }
+    }
+
     private void configureSerializers() {
         // grab some sensible defaults if no serializers are present in the config
         final List<Settings.SerializerSettings> serializerSettings =
@@ -224,7 +258,7 @@
                 if (clazz.getAnnotation(Deprecated.class) != null)
                     logger.warn("The {} serialization class is deprecated.", config.className);
 
-                final MessageSerializer serializer = (MessageSerializer) clazz.newInstance();
+                final MessageSerializer<?> serializer = (MessageSerializer) clazz.newInstance();
                 final Map<String, Graph> graphsDefinedAtStartup = new HashMap<>();
                 for (String graphName : settings.graphs.keySet()) {
                     graphsDefinedAtStartup.put(graphName, graphManager.getGraph(graphName));
@@ -245,7 +279,7 @@
                         Stream.of(serializer.mimeTypesSupported()).map(mimeType -> Pair.with(mimeType, serializer))
         ).forEach(pair -> {
             final String mimeType = pair.getValue0();
-            final MessageSerializer serializer = pair.getValue1();
+            final MessageSerializer<?> serializer = pair.getValue1();
             if (serializers.containsKey(mimeType))
                 logger.info("{} already has {} configured - it will not be replaced by {}, change order of serialization configuration if this is not desired.",
                         mimeType, serializers.get(mimeType).getClass().getName(), serializer.getClass().getName());
@@ -273,58 +307,43 @@
 
         final SslContextBuilder builder;
 
-        // DEPRECATED: If the config has the required, deprecated settings, then use it
-        if (null != sslSettings.keyCertChainFile && null != sslSettings.keyFile) {
-            logger.warn("Using deprecated SSL keyFile support");
-            final File keyCertChainFile = new File(sslSettings.keyCertChainFile);
-            final File keyFile = new File(sslSettings.keyFile);
-            final File trustCertChainFile = null == sslSettings.trustCertChainFile ? null : new File(sslSettings.trustCertChainFile);
+        // Build JSSE SSLContext
+        try {
+            final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
 
-            // note that keyPassword may be null here if the keyFile is not
-            // password-protected. passing null to
-            // trustManager is also ok (default will be used)
-            builder = SslContextBuilder.forServer(keyCertChainFile, keyFile, sslSettings.keyPassword).trustManager(trustCertChainFile);
-        } else {
-
-            // Build JSSE SSLContext
-            try {
-                final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
-
-                // Load private key and signed cert
-                if (null != sslSettings.keyStore) {
-                    final String keyStoreType = null == sslSettings.keyStoreType ? KeyStore.getDefaultType() : sslSettings.keyStoreType;
-                    final KeyStore keystore = KeyStore.getInstance(keyStoreType);
-                    final char[] password = null == sslSettings.keyStorePassword ? null : sslSettings.keyStorePassword.toCharArray();
-                    try (final InputStream in = new FileInputStream(sslSettings.keyStore)) {
-                        keystore.load(in, password);
-                    }
-                    kmf.init(keystore, password);
-                } else {
-                    throw new IllegalStateException("keyStore must be configured when SSL is enabled.");
+            // Load private key and signed cert
+            if (null != sslSettings.keyStore) {
+                final String keyStoreType = null == sslSettings.keyStoreType ? KeyStore.getDefaultType() : sslSettings.keyStoreType;
+                final KeyStore keystore = KeyStore.getInstance(keyStoreType);
+                final char[] password = null == sslSettings.keyStorePassword ? null : sslSettings.keyStorePassword.toCharArray();
+                try (final InputStream in = new FileInputStream(sslSettings.keyStore)) {
+                    keystore.load(in, password);
                 }
-
-                builder = SslContextBuilder.forServer(kmf);
-
-                // Load custom truststore for client auth certs
-                if (null != sslSettings.trustStore) {
-                    final String trustStoreType = null != sslSettings.trustStoreType ? sslSettings.trustStoreType
-                            : sslSettings.keyStoreType != null ? sslSettings.keyStoreType : KeyStore.getDefaultType();
-
-                    final KeyStore truststore = KeyStore.getInstance(trustStoreType);
-                    final char[] password = null == sslSettings.trustStorePassword ? null : sslSettings.trustStorePassword.toCharArray();
-                    try (final InputStream in = new FileInputStream(sslSettings.trustStore)) {
-                        truststore.load(in, password);
-                    }
-                    final TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
-                    tmf.init(truststore);
-                    builder.trustManager(tmf);
-                }
-
-            } catch (UnrecoverableKeyException | NoSuchAlgorithmException | KeyStoreException | CertificateException | IOException e) {
-                logger.error(e.getMessage());
-                throw new RuntimeException("There was an error enabling SSL.", e);
+                kmf.init(keystore, password);
+            } else {
+                throw new IllegalStateException("keyStore must be configured when SSL is enabled.");
             }
 
+            builder = SslContextBuilder.forServer(kmf);
+
+            // Load custom truststore for client auth certs
+            if (null != sslSettings.trustStore) {
+                final String trustStoreType = null != sslSettings.trustStoreType ? sslSettings.trustStoreType
+                            : sslSettings.keyStoreType != null ? sslSettings.keyStoreType : KeyStore.getDefaultType();
+
+                final KeyStore truststore = KeyStore.getInstance(trustStoreType);
+                final char[] password = null == sslSettings.trustStorePassword ? null : sslSettings.trustStorePassword.toCharArray();
+                try (final InputStream in = new FileInputStream(sslSettings.trustStore)) {
+                    truststore.load(in, password);
+                }
+                final TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+                tmf.init(truststore);
+                builder.trustManager(tmf);
+            }
+
+        } catch (UnrecoverableKeyException | NoSuchAlgorithmException | KeyStoreException | CertificateException | IOException e) {
+            logger.error(e.getMessage());
+            throw new RuntimeException("There was an error enabling SSL.", e);
         }
 
         if (null != sslSettings.sslCipherSuites && !sslSettings.sslCipherSuites.isEmpty()) {
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/Context.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/Context.java
index 902a788..0cdb104 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/Context.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/Context.java
@@ -18,16 +18,21 @@
  */
 package org.apache.tinkerpop.gremlin.server;
 
+import org.apache.tinkerpop.gremlin.driver.Tokens;
 import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
 import org.apache.tinkerpop.gremlin.groovy.engine.GremlinExecutor;
 import io.netty.channel.ChannelHandlerContext;
+import org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinScriptChecker;
+import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
 import org.apache.tinkerpop.gremlin.server.handler.Frame;
 import org.apache.tinkerpop.gremlin.structure.Graph;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.Map;
+import java.util.Optional;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -45,6 +50,29 @@
     private final GremlinExecutor gremlinExecutor;
     private final ScheduledExecutorService scheduledExecutorService;
     private final AtomicBoolean finalResponseWritten = new AtomicBoolean();
+    private final long requestTimeout;
+    private final RequestContentType requestContentType;
+    private final Object gremlinArgument;
+
+    /**
+     * The type of the request as determined by the contents of {@link Tokens#ARGS_GREMLIN}.
+     */
+    public enum RequestContentType {
+        /**
+         * Contents is of type {@link Bytecode}.
+         */
+        BYTECODE,
+
+        /**
+         * Contents is of type {@code String}.
+         */
+        SCRIPT,
+
+        /**
+         * Contents are not of a type that is expected.
+         */
+        UNKNOWN
+    }
 
     public Context(final RequestMessage requestMessage, final ChannelHandlerContext ctx,
                    final Settings settings, final GraphManager graphManager,
@@ -55,6 +83,33 @@
         this.graphManager = graphManager;
         this.gremlinExecutor = gremlinExecutor;
         this.scheduledExecutorService = scheduledExecutorService;
+
+        // order of calls matter as one depends on the next
+        this.gremlinArgument = requestMessage.getArgs().get(Tokens.ARGS_GREMLIN);
+        this.requestContentType = determineRequestContents();
+        this.requestTimeout = determineTimeout();
+    }
+
+    /**
+     * The timeout for the request. If the request is a script it examines the script for a timeout setting using
+     * {@code with()}. If that is not found then it examines the request itself to see if the timeout is provided by
+     * {@link Tokens#ARGS_EVAL_TIMEOUT}. If that is not provided then the {@link Settings#evaluationTimeout} is
+     * utilized as the default.
+     */
+    public long getRequestTimeout() {
+        return requestTimeout;
+    }
+
+    public boolean isFinalResponseWritten() {
+        return this.finalResponseWritten.get();
+    }
+
+    public RequestContentType getRequestContentType() {
+        return requestContentType;
+    }
+
+    public Object getGremlinArgument() {
+        return gremlinArgument;
     }
 
     public ScheduledExecutorService getScheduledExecutorService() {
@@ -133,4 +188,28 @@
         }
 
     }
+
+    private RequestContentType determineRequestContents() {
+        if (gremlinArgument instanceof Bytecode)
+            return RequestContentType.BYTECODE;
+        else if (gremlinArgument instanceof String)
+            return RequestContentType.SCRIPT;
+        else
+            return RequestContentType.UNKNOWN;
+    }
+
+    private long determineTimeout() {
+        // timeout override - handle both deprecated and newly named configuration. earlier logic should prevent
+        // both configurations from being submitted at the same time
+        final Map<String, Object> args = requestMessage.getArgs();
+        final long seto = args.containsKey(Tokens.ARGS_EVAL_TIMEOUT) ?
+                ((Number) args.get(Tokens.ARGS_EVAL_TIMEOUT)).longValue() : settings.getEvaluationTimeout();
+
+        // override the timeout if the lifecycle has a value assigned. if the script contains with(timeout)
+        // options then allow that value to override what's provided on the lifecycle
+        final Optional<Long> timeoutDefinedInScript = requestContentType == RequestContentType.SCRIPT ?
+                GremlinScriptChecker.parse(gremlinArgument.toString()).getTimeout() : Optional.empty();
+
+        return timeoutDefinedInScript.orElse(seto);
+    }
 }
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/GraphManager.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/GraphManager.java
index b64bba4..e8acaf2 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/GraphManager.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/GraphManager.java
@@ -114,4 +114,14 @@
      * from the {@code GraphManager}.
      */
     public Graph removeGraph(final String graphName) throws Exception;
+
+    /**
+     * Determines if any {@link Graph} instances that support transactions have open transactions.
+     */
+    public default boolean hasAnyOpenTransactions() {
+        return getGraphNames().stream().anyMatch(graphName -> {
+            final Graph graph = getGraph(graphName);
+            return graph.features().graph().supportsTransactions() && graph.tx().isOpen();
+        });
+    }
 }
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/GremlinServer.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/GremlinServer.java
index 2a1adf7..d022ffb 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/GremlinServer.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/GremlinServer.java
@@ -78,6 +78,7 @@
     private final ExecutorService gremlinExecutorService;
     private final ServerGremlinExecutor serverGremlinExecutor;
     private final boolean isEpollEnabled;
+    private Channelizer channelizer;
 
     /**
      * Construct a Gremlin Server instance from {@link Settings}.
@@ -159,7 +160,7 @@
                 }
             });
 
-            final Channelizer channelizer = createChannelizer(settings);
+            channelizer = createChannelizer(settings);
             channelizer.init(serverGremlinExecutor);
             b.group(bossGroup, workerGroup)
                     .childHandler(channelizer);
@@ -284,8 +285,11 @@
             }
 
             try {
-                if (gremlinExecutorService != null)
-                    gremlinExecutorService.awaitTermination(30000, TimeUnit.MILLISECONDS);
+                if (gremlinExecutorService != null) {
+                    if (!gremlinExecutorService.awaitTermination(30000, TimeUnit.MILLISECONDS)) {
+                        logger.warn("Gremlin thread pool did not fully terminate - continuing with shutdown process");
+                    }
+                }
             } catch (InterruptedException ie) {
                 logger.warn("Timeout waiting for Gremlin thread pool to shutdown - continuing with shutdown process.");
             }
@@ -330,6 +334,10 @@
         return serverGremlinExecutor;
     }
 
+    public Channelizer getChannelizer() {
+        return channelizer;
+    }
+
     public static void main(final String[] args) throws Exception {
         // add to vm options: -Dlog4j.configuration=file:conf/log4j.properties
         printHeader();
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/ResponseHandlerContext.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/ResponseHandlerContext.java
deleted file mode 100644
index d927fd8..0000000
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/ResponseHandlerContext.java
+++ /dev/null
@@ -1,92 +0,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.
- */
-package org.apache.tinkerpop.gremlin.server;
-
-import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
-import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
-import org.apache.tinkerpop.gremlin.server.handler.Frame;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * A context for asynchronously writing response messages related to a particular request.
- * <p>The "write" methods of this class ensure that at most one {@link ResponseStatusCode#isFinalResponse() final}
- * response message is written to the underlying channel. Attempts to write more than one final response message will
- * be ignored with a warning log message.</p>
- * <p>Note: an object of this class should be used instead of writing to the channel directly when multiple threads
- * are expected to produce final response messages concurrently. Callers must ensure that the same
- * {@link ResponseHandlerContext} is used by all threads writing response messages for the same request.</p>
- *
- * @author Dmitri Bourlatchkov
- * @deprecated As of release 3.3.8, replaced by {@link Context}.
- */
-@Deprecated
-public class ResponseHandlerContext {
-    private static final Logger logger = LoggerFactory.getLogger(ResponseHandlerContext.class);
-
-    private final Context context;
-    private final AtomicBoolean finalResponseWritten = new AtomicBoolean();
-
-    public ResponseHandlerContext(final Context context) {
-        this.context = context;
-    }
-
-    public Context getContext() {
-        return context;
-    }
-
-    /**
-     * Writes a response message to the underlying channel while ensuring that at most one
-     * {@link ResponseStatusCode#isFinalResponse() final} response is written.
-     * <p>Note: this method should be used instead of writing to the channel directly when multiple threads
-     * are expected to produce response messages concurrently.</p>
-     * <p>Attempts to write more than one final response message will be ignored.</p>
-     * @see #writeAndFlush(ResponseStatusCode, Object)
-     */
-    public void writeAndFlush(final ResponseMessage message) {
-        writeAndFlush(message.getStatus().getCode(), message);
-    }
-
-    /**
-     * Writes a response message to the underlying channel while ensuring that at most one
-     * {@link ResponseStatusCode#isFinalResponse() final} response is written.
-     * <p>The caller must make sure that the provided response status code matches the content of the message.</p>
-     * <p>Note: this method should be used instead of writing to the channel directly when multiple threads
-     * are expected to produce response messages concurrently.</p>
-     * <p>Attempts to write more than one final response message will be ignored.</p>
-     * @see #writeAndFlush(ResponseMessage)
-     */
-    public void writeAndFlush(final ResponseStatusCode code, final Object responseMessage) {
-        final boolean messageIsFinal = code.isFinalResponse();
-        if(finalResponseWritten.compareAndSet(false, messageIsFinal)) {
-            context.getChannelHandlerContext().writeAndFlush(responseMessage);
-        } else {
-            if (responseMessage instanceof Frame) {
-                ((Frame) responseMessage).tryRelease();
-            }
-
-            final String logMessage = String.format("Another final response message was already written for request %s, ignoring response code: %s",
-                    context.getRequestMessage().getRequestId(), code);
-            logger.warn(logMessage);
-        }
-
-    }
-}
\ No newline at end of file
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/Settings.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/Settings.java
index b01b7e5..149372f 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/Settings.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/Settings.java
@@ -27,11 +27,16 @@
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
 import org.apache.tinkerpop.gremlin.server.auth.AllowAllAuthenticator;
 import org.apache.tinkerpop.gremlin.server.auth.Authenticator;
+import org.apache.tinkerpop.gremlin.server.authz.Authorizer;
+import org.apache.tinkerpop.gremlin.server.channel.UnifiedChannelizer;
 import org.apache.tinkerpop.gremlin.server.channel.WebSocketChannelizer;
 import org.apache.tinkerpop.gremlin.server.handler.AbstractAuthenticationHandler;
+import org.apache.tinkerpop.gremlin.server.handler.Session;
 import org.apache.tinkerpop.gremlin.server.util.DefaultGraphManager;
 import org.apache.tinkerpop.gremlin.server.util.LifeCycleHook;
 import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.yaml.snakeyaml.TypeDescription;
 import org.yaml.snakeyaml.Yaml;
 import org.yaml.snakeyaml.constructor.Constructor;
@@ -59,6 +64,8 @@
  */
 public class Settings {
 
+    private static final Logger logger = LoggerFactory.getLogger(Settings.class);
+
     public Settings() {
         // setup some sensible defaults like gremlin-groovy
         scriptEngines = new HashMap<>();
@@ -101,16 +108,6 @@
     public int threadPoolBoss = 1;
 
     /**
-     * Time in milliseconds to wait for a request (script or bytecode) to complete execution.  Defaults to -1 and
-     * thus defers to {@link #evaluationTimeout} for this configuration. When set to something greater than -1 then
-     * this configuration is used.
-     *
-     * @deprecated As of release 3.3.9, replaced by {@link #evaluationTimeout}.
-     */
-    @Deprecated
-    public long scriptEvaluationTimeout = -1L;
-
-    /**
      * Time in milliseconds to wait for a request (script or bytecode) to complete execution. Defaults to 30000.
      */
     public long evaluationTimeout = 30000L;
@@ -202,6 +199,62 @@
     public String graphManager = DefaultGraphManager.class.getName();
 
     /**
+     * Maximum size the general processing queue can grow before starting to reject requests. The general processing
+     * queue is managed by a thread pool that has its size determined by {@link #gremlinPool}. All incoming requests
+     * will be processed by this thread pool. If the threads are exhausted, the requests will queue to the size
+     * specified by this value after which they will begin to reject the requests.
+     * <p/>
+     * This value should be taken in account with the {@link #maxSessionTaskQueueSize} which is related in some
+     * respects. A request that starts a new {@link Session} is handled by this queue, but additional requests to a
+     * created {@link Session} will queue separately given that setting per session.
+     * <p/>
+     * By default this value is set to 8192.
+     */
+    public int maxWorkQueueSize = 8192;
+
+    /**
+     * Maximum size that an individual {@link Session} can queue requests before starting to reject them. Note that this
+     * configuration only applies to the {@link UnifiedChannelizer}. By default this value is set to 4096.
+     *
+     * @see #maxWorkQueueSize
+     */
+    public int maxSessionTaskQueueSize = 4096;
+
+    /**
+     * Maximum number of parameters that can be passed on a request. Larger numbers may impact performance for scripts.
+     * The default is 16 and this setting only applies to the {@link UnifiedChannelizer}.
+     */
+    public int maxParameters = 16;
+
+    /**
+     * The time in milliseconds that a {@link UnifiedChannelizer} session can exist. This value cannot be extended
+     * beyond this value irrespective of the number of requests and their individual timeouts. Requests must complete
+     * within this time frame. If this timeout is reached while there is a running evaluation, there will be an attempt
+     * to interrupt it which will result in a timeout error to the client. If there are existing requests enqueued for
+     * the session when this timeout is reached, those requests will not be executed and will be closed with server
+     * errors. Open transactions will be issued a rollback. The default is 10 minutes.
+     */
+    public long sessionLifetimeTimeout = 600000;
+
+    /**
+     * Enable the global function cache for sessions when using the {@link UnifiedChannelizer}. This setting is only
+     * relevant when {@link #useGlobalFunctionCacheForSessions} is {@code false}. When {@link true} it means that
+     * functions created in one request to a session remain available on the next request to that session.
+     */
+    public boolean useGlobalFunctionCacheForSessions = true;
+
+    /**
+     * When {@code true} and using the {@link UnifiedChannelizer} the same engine that will be used to server
+     * sessionless requests will also be use to serve sessions. The default value of {@code true} is recommended as
+     * it reduces the amount of object creation required for each session and should generally lead to better
+     * performance especially if the expectation is that there will be many sessions being created and destroyed
+     * rapidly. Setting this value to {@code false} is mostly present to support specific use cases that may require
+     * each session having its own engine or to match previous functionality provided by the older channelizers
+     * produced prior to 3.5.0.
+     */
+    public boolean useCommonEngineForSessions = true;
+
+    /**
      * Configured metrics for Gremlin Server.
      */
     public ServerMetrics metrics = null;
@@ -230,6 +283,13 @@
 
     public AuthenticationSettings authentication = new AuthenticationSettings();
 
+    public AuthorizationSettings authorization = new AuthorizationSettings();
+
+    /**
+     * Enable audit logging of authenticated users and gremlin evaluation requests.
+     */
+    public Boolean enableAuditLog = false;
+
     /**
      * Custom settings for {@link OpProcessor} implementations. Implementations are loaded via
      * {@link ServiceLoader} but custom configurations can be supplied through this configuration.
@@ -255,7 +315,7 @@
     }
 
     public long getEvaluationTimeout() {
-        return -1 == scriptEvaluationTimeout ? evaluationTimeout : scriptEvaluationTimeout;
+        return evaluationTimeout;
     }
 
     /**
@@ -337,7 +397,15 @@
 
         final Constructor constructor = createDefaultYamlConstructor();
         final Yaml yaml = new Yaml(constructor);
-        return yaml.loadAs(stream, Settings.class);
+        final Settings settings = yaml.loadAs(stream, Settings.class);
+        if (settings.authentication.enableAuditLog && settings.enableAuditLog) {
+            logger.warn("Both authentication.enableAuditLog and settings.enableAuditLog " +
+                        "are enabled, so auditable events are logged twice.");
+        }
+        if (settings.authentication.enableAuditLog && !settings.enableAuditLog) {
+            logger.warn("Configuration property 'authentication.enableAuditLog' is deprecated, use 'enableAuditLog' instead.");
+        }
+        return settings;
     }
 
     /**
@@ -438,7 +506,10 @@
 
         /**
          * Enable audit logging of authenticated users and gremlin evaluation requests.
+         * @deprecated As of release 3.5.0, replaced by {@link Settings#enableAuditLog} with slight changes in the
+         * log message format.
          */
+        @Deprecated
         public boolean enableAuditLog = false;
 
         /**
@@ -449,6 +520,23 @@
     }
 
     /**
+     * Settings for the {@link Authenticator} implementation.
+     */
+    public static class AuthorizationSettings {
+        /**
+         * The fully qualified class name of the {@link Authorizer} implementation. This class name will be
+         * used to load the implementation from the classpath. Defaults to null when not specified.
+         */
+        public String authorizer = null;
+
+        /**
+         * A {@link Map} containing {@link Authorizer} specific configurations. Consult the
+         * {@link Authorizer} implementation for specifics on what configurations are expected.
+         */
+        public Map<String, Object> config = null;
+    }
+
+    /**
      * Settings to configure SSL support.
      */
     public static class SslSettings {
@@ -458,41 +546,6 @@
         public boolean enabled = false;
 
         /**
-         * The X.509 certificate chain file in PEM format.
-         *
-         * @deprecated As of release 3.2.10, replaced by {@link #keyStore}
-         */
-        @Deprecated
-        public String keyCertChainFile = null;
-
-        /**
-         * The PKCS#8 private key file in PEM format.
-         *
-         * @deprecated As of release 3.2.10, replaced by {@link #keyStore}
-         */
-        @Deprecated
-        public String keyFile = null;
-
-        /**
-         * The password of the {@link #keyFile}, or {@code null} if it's not
-         * password-protected.
-         *
-         * @deprecated As of release 3.2.10, replaced by {@link #keyStorePassword}
-         */
-        @Deprecated
-        public String keyPassword = null;
-
-        /**
-         * Trusted certificates for verifying the remote endpoint's certificate. The
-         * file should contain an X.509 certificate chain in PEM format. {@code null}
-         * uses the system default.
-         *
-         * @deprecated As of release 3.2.10, replaced by {@link #trustStore}
-         */
-        @Deprecated
-        public String trustCertChainFile = null;
-
-        /**
          * The file location of the private key in JKS or PKCS#12 format.
          */
         public String keyStore;
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/auth/Krb5Authenticator.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/auth/Krb5Authenticator.java
index 190379c..69f556a 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/auth/Krb5Authenticator.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/auth/Krb5Authenticator.java
@@ -73,7 +73,7 @@
             principalName = (String) config.get(PRINCIPAL_KEY);
             subject = JaasKrbUtil.loginUsingKeytab(principalName, keytabFile);
         } catch (Exception e) {
-            logger.warn("Failed to login to kdc");
+            logger.warn("Failed to login to kdc:" + e.getMessage());
         }
         
         logger.debug("Done logging in to kdc");
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/authz/AuthorizationException.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/authz/AuthorizationException.java
new file mode 100644
index 0000000..1103027
--- /dev/null
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/authz/AuthorizationException.java
@@ -0,0 +1,47 @@
+/*
+ * 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.server.authz;
+
+/**
+ * An exception that occurs during authorization, i.e. when a requested resource needed for a response to an
+ * evaluation request is not allowed for this user.
+ *
+ * @author Marc de Lignie
+ */
+public class AuthorizationException extends Exception {
+    public AuthorizationException() {
+    }
+
+    public AuthorizationException(final String message) {
+        super(message);
+    }
+
+    public AuthorizationException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
+
+    public AuthorizationException(final Throwable cause) {
+        super(cause);
+    }
+
+    public AuthorizationException(final String message, final Throwable cause, final boolean enableSuppression,
+                                  final boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+}
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/authz/Authorizer.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/authz/Authorizer.java
new file mode 100644
index 0000000..c32b78a
--- /dev/null
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/authz/Authorizer.java
@@ -0,0 +1,62 @@
+/*
+ * 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.server.authz;
+
+import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
+import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
+import org.apache.tinkerpop.gremlin.server.auth.AuthenticatedUser;
+
+import java.util.Map;
+
+
+/**
+ * Provides the interface for authorizing a user per request.
+ *
+ * @author Marc de Lignie
+ */
+public interface Authorizer {
+    /**
+     * This method is called once upon system startup to initialize the {@code Authorizer}.
+     */
+    public void setup(final Map<String,Object> config) throws AuthorizationException;
+
+    /**
+     * Checks whether a user is authorized to have a gremlin bytecode request from a client answered and raises an
+     * {@link AuthorizationException} if this is not the case. The returned bytecde is used for further processing of
+     * the request.
+     *
+     * @param user {@link AuthenticatedUser} that needs authorization.
+     * @param bytecode The gremlin {@link Bytecode} request to authorize the user for.
+     * @param aliases A {@link Map} with a single key/value pair that maps the name of the {@link TraversalSource} in the
+     *                {@link Bytecode} request to name of one configured in Gremlin Server.
+     * @return The original or modified {@link Bytecode} to be used for further processing.
+     */
+    public Bytecode authorize(final AuthenticatedUser user, final Bytecode bytecode, final Map<String, String> aliases) throws AuthorizationException;
+
+    /**
+     * Checks whether a user is authorized to have a script request from a gremlin client answered and raises an
+     * {@link AuthorizationException} if this is not the case.
+     *
+     * @param user {@link AuthenticatedUser} that needs authorization.
+     * @param msg {@link RequestMessage} in which the {@link org.apache.tinkerpop.gremlin.driver.Tokens}.ARGS_GREMLIN argument can contain an arbitrary succession of script statements.
+     */
+    public void authorize(final AuthenticatedUser user, final RequestMessage msg) throws AuthorizationException;
+
+}
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/channel/HttpChannelizer.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/channel/HttpChannelizer.java
index d65fdf2..be2a7af 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/channel/HttpChannelizer.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/channel/HttpChannelizer.java
@@ -18,12 +18,14 @@
  */
 package org.apache.tinkerpop.gremlin.server.channel;
 
+import io.netty.channel.ChannelInboundHandlerAdapter;
 import org.apache.tinkerpop.gremlin.server.AbstractChannelizer;
 import org.apache.tinkerpop.gremlin.server.Channelizer;
 import org.apache.tinkerpop.gremlin.server.Settings;
 import org.apache.tinkerpop.gremlin.server.auth.AllowAllAuthenticator;
 import org.apache.tinkerpop.gremlin.server.handler.AbstractAuthenticationHandler;
 import org.apache.tinkerpop.gremlin.server.handler.HttpBasicAuthenticationHandler;
+import org.apache.tinkerpop.gremlin.server.handler.HttpBasicAuthorizationHandler;
 import org.apache.tinkerpop.gremlin.server.handler.HttpGremlinEndpointHandler;
 import io.netty.channel.ChannelPipeline;
 import io.netty.handler.codec.http.HttpObjectAggregator;
@@ -43,7 +45,6 @@
     private static final Logger logger = LoggerFactory.getLogger(HttpChannelizer.class);
 
     private HttpGremlinEndpointHandler httpGremlinEndpointHandler;
-    private AbstractAuthenticationHandler authenticationHandler;
 
     @Override
     public void init(final ServerGremlinExecutor serverGremlinExecutor) {
@@ -61,29 +62,36 @@
         if (logger.isDebugEnabled())
             pipeline.addLast(new LoggingHandler("http-io", LogLevel.DEBUG));
 
-        pipeline.addLast(new HttpObjectAggregator(settings.maxContentLength));
+        final HttpObjectAggregator aggregator = new HttpObjectAggregator(settings.maxContentLength);
+        aggregator.setMaxCumulationBufferComponents(settings.maxAccumulationBufferComponents);
+        pipeline.addLast(PIPELINE_HTTP_AGGREGATOR, aggregator);
 
         if (authenticator != null) {
-            // Cannot add the same handler instance to multiple times unless
+            // Cannot add the same handler instance multiple times unless
             // it is marked as @Sharable, indicating a race condition will
             // not occur. It may not be a safe assumption that the handler
             // is sharable so create a new handler each time.
-            authenticationHandler = authenticator.getClass() == AllowAllAuthenticator.class ?
-                    null : instantiateAuthenticationHandler(settings.authentication);
+            final AbstractAuthenticationHandler authenticationHandler = authenticator.getClass() == AllowAllAuthenticator.class ?
+                    null : instantiateAuthenticationHandler(settings);
             if (authenticationHandler != null)
                 pipeline.addLast(PIPELINE_AUTHENTICATOR, authenticationHandler);
         }
 
+        if (authorizer != null) {
+            final ChannelInboundHandlerAdapter authorizationHandler = new HttpBasicAuthorizationHandler(authorizer);
+            pipeline.addLast(PIPELINE_AUTHORIZER, authorizationHandler);
+        }
+
         pipeline.addLast("http-gremlin-handler", httpGremlinEndpointHandler);
     }
 
-    private AbstractAuthenticationHandler instantiateAuthenticationHandler(final Settings.AuthenticationSettings authSettings) {
-        final String authHandlerClass = authSettings.authenticationHandler;
+    private AbstractAuthenticationHandler instantiateAuthenticationHandler(final Settings settings) {
+        final String authHandlerClass = settings.authentication.authenticationHandler;
         if (authHandlerClass == null) {
             //Keep things backwards compatible
-            return new HttpBasicAuthenticationHandler(authenticator, authSettings);
+            return new HttpBasicAuthenticationHandler(authenticator, settings);
         } else {
-            return createAuthenticationHandler(authSettings);
+            return createAuthenticationHandler(settings);
         }
     }
 
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/channel/NioChannelizer.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/channel/NioChannelizer.java
deleted file mode 100644
index 8043580..0000000
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/channel/NioChannelizer.java
+++ /dev/null
@@ -1,78 +0,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.
- */
-package org.apache.tinkerpop.gremlin.server.channel;
-
-import org.apache.tinkerpop.gremlin.driver.simple.WebSocketClient;
-import org.apache.tinkerpop.gremlin.server.AbstractChannelizer;
-import org.apache.tinkerpop.gremlin.server.Channelizer;
-import org.apache.tinkerpop.gremlin.server.auth.AllowAllAuthenticator;
-import org.apache.tinkerpop.gremlin.server.handler.GremlinResponseFrameEncoder;
-import org.apache.tinkerpop.gremlin.server.handler.NioGremlinBinaryRequestDecoder;
-import io.netty.channel.ChannelPipeline;
-import io.netty.handler.logging.LogLevel;
-import io.netty.handler.logging.LoggingHandler;
-import org.apache.tinkerpop.gremlin.server.handler.NioGremlinResponseFrameEncoder;
-import org.apache.tinkerpop.gremlin.server.handler.SaslAuthenticationHandler;
-import org.apache.tinkerpop.gremlin.server.util.ServerGremlinExecutor;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * A {@link Channelizer} that exposes an NIO-based Gremlin endpoint with a custom protocol.
- *
- * @author Stephen Mallette (http://stephen.genoprime.com)
- * @deprecated As of release 3.3.10, not replaced, use {@link WebSocketClient}.
- */
-@Deprecated
-public class NioChannelizer extends AbstractChannelizer {
-    private static final Logger logger = LoggerFactory.getLogger(NioChannelizer.class);
-
-    private SaslAuthenticationHandler authenticationHandler;
-    private GremlinResponseFrameEncoder gremlinResponseFrameEncoder;
-    private NioGremlinResponseFrameEncoder nioGremlinResponseFrameEncoder;
-
-    @Override
-    public void init(final ServerGremlinExecutor serverGremlinExecutor) {
-        super.init(serverGremlinExecutor);
-
-        // configure authentication - null means don't bother to add authentication to the pipeline
-        if (authenticator != null)
-            authenticationHandler = authenticator.getClass() == AllowAllAuthenticator.class ?
-                    null : new SaslAuthenticationHandler(authenticator, settings.authentication);
-
-        gremlinResponseFrameEncoder = new GremlinResponseFrameEncoder();
-        nioGremlinResponseFrameEncoder = new NioGremlinResponseFrameEncoder();
-    }
-
-    @Override
-    public void configure(final ChannelPipeline pipeline) {
-        if (logger.isDebugEnabled())
-            pipeline.addLast(new LoggingHandler("log-io", LogLevel.DEBUG));
-
-        pipeline.addLast("nio-frame-encoder", nioGremlinResponseFrameEncoder);
-        pipeline.addLast("response-frame-encoder", gremlinResponseFrameEncoder);
-        pipeline.addLast("request-binary-decoder", new NioGremlinBinaryRequestDecoder(serializers));
-
-        if (logger.isDebugEnabled())
-            pipeline.addLast(new LoggingHandler("log-codec", LogLevel.DEBUG));
-
-        if (authenticationHandler != null)
-            pipeline.addLast(PIPELINE_AUTHENTICATOR, authenticationHandler);
-    }
-}
\ No newline at end of file
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/channel/UnifiedChannelizer.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/channel/UnifiedChannelizer.java
new file mode 100644
index 0000000..f3e910e
--- /dev/null
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/channel/UnifiedChannelizer.java
@@ -0,0 +1,86 @@
+/*
+ * 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.server.channel;
+
+import io.netty.channel.ChannelPipeline;
+import org.apache.tinkerpop.gremlin.server.AbstractChannelizer;
+import org.apache.tinkerpop.gremlin.server.Channelizer;
+import org.apache.tinkerpop.gremlin.server.handler.HttpGremlinEndpointHandler;
+import org.apache.tinkerpop.gremlin.server.handler.UnifiedHandler;
+import org.apache.tinkerpop.gremlin.server.handler.WsAndHttpChannelizerHandler;
+import org.apache.tinkerpop.gremlin.server.util.ServerGremlinExecutor;
+
+/**
+ * A {@link Channelizer} that supports websocket and HTTP requests and does so with the most streamlined processing
+ * model for Gremlin Server introduced with 3.5.0.
+ */
+public class UnifiedChannelizer extends AbstractChannelizer {
+
+    private WsAndHttpChannelizerHandler wsAndHttpChannelizerHandler;
+    private UnifiedHandler unifiedHandler;
+    protected static final String PIPELINE_UNIFIED = "unified";
+
+    @Override
+    public void init(final ServerGremlinExecutor serverGremlinExecutor) {
+        super.init(serverGremlinExecutor);
+
+        wsAndHttpChannelizerHandler = new WsAndHttpChannelizerHandler();
+        wsAndHttpChannelizerHandler.init(serverGremlinExecutor, new HttpGremlinEndpointHandler(serializers, gremlinExecutor, graphManager, settings));
+
+        // these handlers don't share any state and can thus be initialized once per pipeline
+        unifiedHandler = new UnifiedHandler(settings, graphManager, gremlinExecutor, scheduledExecutorService, this);
+    }
+
+    @Override
+    public void configure(final ChannelPipeline pipeline) {
+        wsAndHttpChannelizerHandler.configure(pipeline);
+        pipeline.addAfter(PIPELINE_HTTP_REQUEST_DECODER, "WsAndHttpChannelizerHandler", wsAndHttpChannelizerHandler);
+    }
+
+    @Override
+    public void finalize(final ChannelPipeline pipeline) {
+        super.finalize(pipeline);
+
+        // currently the AbstractChannelizer adds the following handlers which prior to 3.5.0 were essentially
+        // required by any Gremlin-processing pipeline you could think of because they provided the functionality
+        // of the OpProcessor infrastructure. the OpProcessor infrastructure is on its way to deprecation after
+        // TINKERPOP-2245 which introduced this channelizer implementation. since AbstractChannelizer does a nice
+        // job of rigging up the rest of the pipeline it seemed to make sense to leave it unchanged to ensure it
+        // does not break anyone's channelizers that may depend on it (including TinkerPop's and simply remove
+        // those bits here. in the future, when we remove OpProcessor stuff completely we can clean this up.
+        pipeline.remove(PIPELINE_OP_SELECTOR);
+        pipeline.remove(PIPELINE_OP_EXECUTOR);
+
+        pipeline.addLast(PIPELINE_UNIFIED, unifiedHandler);
+    }
+
+    public UnifiedHandler getUnifiedHandler() {
+        return unifiedHandler;
+    }
+
+    @Override
+    public boolean supportsIdleMonitor() {
+        return true;
+    }
+
+    @Override
+    public Object createIdleDetectionMessage() {
+        return wsAndHttpChannelizerHandler.getWsChannelizer().createIdleDetectionMessage();
+    }
+}
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/channel/WebSocketChannelizer.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/channel/WebSocketChannelizer.java
index 09bcdd2..a1864fd 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/channel/WebSocketChannelizer.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/channel/WebSocketChannelizer.java
@@ -18,6 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.server.channel;
 
+import io.netty.channel.ChannelInboundHandlerAdapter;
 import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
 import io.netty.handler.codec.http.websocketx.WebSocketDecoderConfig;
 import org.apache.tinkerpop.gremlin.server.AbstractChannelizer;
@@ -25,6 +26,7 @@
 import org.apache.tinkerpop.gremlin.server.auth.AllowAllAuthenticator;
 import org.apache.tinkerpop.gremlin.server.handler.AbstractAuthenticationHandler;
 import org.apache.tinkerpop.gremlin.server.Settings;
+import org.apache.tinkerpop.gremlin.server.handler.WebSocketAuthorizationHandler;
 import org.apache.tinkerpop.gremlin.server.handler.SaslAuthenticationHandler;
 import org.apache.tinkerpop.gremlin.server.handler.WsGremlinBinaryRequestDecoder;
 import org.apache.tinkerpop.gremlin.server.handler.WsGremlinCloseRequestDecoder;
@@ -57,6 +59,7 @@
     private WsGremlinResponseFrameEncoder wsGremlinResponseFrameEncoder;
     private WsGremlinCloseRequestDecoder wsGremlinCloseRequestDecoder;
     private AbstractAuthenticationHandler authenticationHandler;
+    private ChannelInboundHandlerAdapter authorizationHandler;
 
     @Override
     public void init(final ServerGremlinExecutor serverGremlinExecutor) {
@@ -69,15 +72,20 @@
         wsGremlinResponseFrameEncoder = new WsGremlinResponseFrameEncoder();
 
         // configure authentication - null means don't bother to add authentication to the pipeline
-        if (authenticator != null)
-            authenticationHandler = authenticator.getClass() == AllowAllAuthenticator.class ?
-                    null : instantiateAuthenticationHandler(settings.authentication);
+        authenticationHandler = authenticator.getClass() == AllowAllAuthenticator.class ?
+            null : instantiateAuthenticationHandler(settings);
+        if (authorizer != null) {
+            authorizationHandler = new WebSocketAuthorizationHandler(authorizer);
+        }
     }
 
     @Override
     public void configure(final ChannelPipeline pipeline) {
+
         if (logger.isDebugEnabled())
-            pipeline.addLast(new LoggingHandler("log-io", LogLevel.DEBUG));
+            pipeline.addLast(new LoggingHandler("log-encoder-aggregator", LogLevel.DEBUG));
+
+        pipeline.addLast(PIPELINE_HTTP_RESPONSE_ENCODER, new HttpResponseEncoder());
 
         logger.debug("HttpRequestDecoder settings - maxInitialLineLength={}, maxHeaderSize={}, maxChunkSize={}",
                 settings.maxInitialLineLength, settings.maxHeaderSize, settings.maxChunkSize);
@@ -90,12 +98,7 @@
                 settings.maxContentLength, settings.maxAccumulationBufferComponents);
         final HttpObjectAggregator aggregator = new HttpObjectAggregator(settings.maxContentLength);
         aggregator.setMaxCumulationBufferComponents(settings.maxAccumulationBufferComponents);
-        pipeline.addLast("aggregator", aggregator);
-
-        if (logger.isDebugEnabled())
-            pipeline.addLast(new LoggingHandler("log-aggregator-encoder", LogLevel.DEBUG));
-
-        pipeline.addLast(PIPELINE_HTTP_RESPONSE_ENCODER, new HttpResponseEncoder());
+        pipeline.addLast(PIPELINE_HTTP_AGGREGATOR, aggregator);
         // Add compression extension for WebSocket defined in https://tools.ietf.org/html/rfc7692
         pipeline.addLast(PIPELINE_WEBSOCKET_SERVER_COMPRESSION, new WebSocketServerCompressionHandler());
 
@@ -120,6 +123,9 @@
 
         if (authenticationHandler != null)
             pipeline.addLast(PIPELINE_AUTHENTICATOR, authenticationHandler);
+
+        if (authorizationHandler != null)
+            pipeline.addLast(PIPELINE_AUTHORIZER, authorizationHandler);
     }
 
     @Override
@@ -132,13 +138,13 @@
         return new PingWebSocketFrame();
     }
 
-    private AbstractAuthenticationHandler instantiateAuthenticationHandler(final Settings.AuthenticationSettings authSettings) {
-        final String authenticationHandler = authSettings.authenticationHandler;
+    private AbstractAuthenticationHandler instantiateAuthenticationHandler(final Settings settings) {
+        final String authenticationHandler = settings.authentication.authenticationHandler;
         if (authenticationHandler == null) {
             //Keep things backwards compatible
-            return new SaslAuthenticationHandler(authenticator, authSettings);
+            return new SaslAuthenticationHandler(authenticator, settings);
         } else {
-            return createAuthenticationHandler(authSettings);
+            return createAuthenticationHandler(settings);
         }
     }
 }
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/AbstractAuthenticationHandler.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/AbstractAuthenticationHandler.java
index 026ad59..074e4ab 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/AbstractAuthenticationHandler.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/AbstractAuthenticationHandler.java
@@ -21,15 +21,25 @@
 import org.apache.tinkerpop.gremlin.server.auth.Authenticator;
 
 import io.netty.channel.ChannelInboundHandlerAdapter;
+import org.apache.tinkerpop.gremlin.server.authz.Authorizer;
 
 /**
  * Provides an abstraction point to allow for http auth schemes beyond basic auth.
  */
 public abstract class AbstractAuthenticationHandler extends ChannelInboundHandlerAdapter {
     protected final Authenticator authenticator;
+    protected final Authorizer authorizer;
 
+    /**
+     * @deprecated As of release 3.5.0, replaced by {@link #AbstractAuthenticationHandler(Authenticator, Authorizer)}.
+     */
+    @Deprecated
     public AbstractAuthenticationHandler(final Authenticator authenticator) {
-        this.authenticator = authenticator;
+        this(authenticator, null);
     }
 
+    public AbstractAuthenticationHandler(final Authenticator authenticator, final Authorizer authorizer) {
+        this.authenticator = authenticator;
+        this.authorizer = authorizer;
+    }
 }
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/AbstractSession.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/AbstractSession.java
new file mode 100644
index 0000000..2a50785
--- /dev/null
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/AbstractSession.java
@@ -0,0 +1,847 @@
+/*
+ * 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.server.handler;
+
+import com.codahale.metrics.Timer;
+import groovy.lang.GroovyRuntimeException;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandlerContext;
+import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.apache.tinkerpop.gremlin.driver.Client;
+import org.apache.tinkerpop.gremlin.driver.MessageSerializer;
+import org.apache.tinkerpop.gremlin.driver.Tokens;
+import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
+import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
+import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
+import org.apache.tinkerpop.gremlin.driver.ser.MessageTextSerializer;
+import org.apache.tinkerpop.gremlin.groovy.engine.GremlinExecutor;
+import org.apache.tinkerpop.gremlin.groovy.jsr223.TimedInterruptTimeoutException;
+import org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngine;
+import org.apache.tinkerpop.gremlin.jsr223.JavaTranslator;
+import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
+import org.apache.tinkerpop.gremlin.process.traversal.GraphOp;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.VerificationException;
+import org.apache.tinkerpop.gremlin.process.traversal.util.BytecodeHelper;
+import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalInterruptedException;
+import org.apache.tinkerpop.gremlin.server.GraphManager;
+import org.apache.tinkerpop.gremlin.server.GremlinServer;
+import org.apache.tinkerpop.gremlin.server.Settings;
+import org.apache.tinkerpop.gremlin.server.auth.AuthenticatedUser;
+import org.apache.tinkerpop.gremlin.server.util.ExceptionHelper;
+import org.apache.tinkerpop.gremlin.server.util.TraverserIterator;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.Transaction;
+import org.apache.tinkerpop.gremlin.structure.util.TemporaryException;
+import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
+import org.codehaus.groovy.control.MultipleCompilationErrorsException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.script.Bindings;
+import javax.script.ScriptException;
+import javax.script.SimpleBindings;
+import java.io.InterruptedIOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Stream;
+
+import static org.apache.tinkerpop.gremlin.process.traversal.GraphOp.TX_COMMIT;
+import static org.apache.tinkerpop.gremlin.process.traversal.GraphOp.TX_ROLLBACK;
+
+/**
+ * A base implementation of {@link Session} which offers some common functionality that matches typical Gremlin Server
+ * request response expectations for script, bytecode and graph operations. The class is designed to be extended but
+ * take care in understanding the way that different methods are called as they do depend on one another a bit. It
+ * maybe best to examine the source code to determine how best to use this class or to extend from the higher order
+ * classes of {@link SingleTaskSession} or {@link MultiTaskSession}.
+ */
+public abstract class AbstractSession implements Session, AutoCloseable {
+    private static final Logger logger = LoggerFactory.getLogger(AbstractSession.class);
+    private static final Logger auditLogger = LoggerFactory.getLogger(GremlinServer.AUDIT_LOGGER_NAME);
+
+    private final boolean sessionIdOnRequest;
+    private final Channel initialChannel;
+    private final boolean transactionManaged;
+    private final String sessionId;
+    private final AtomicReference<ScheduledFuture<?>> sessionCancelFuture = new AtomicReference<>();
+    private final AtomicReference<Future<?>> sessionFuture = new AtomicReference<>();
+    private long actualTimeoutLengthWhenClosed = 0;
+
+    /**
+     * The session thread is a reference to the thread that is running the session and should be set by an
+     * implementation as the first line of the {@link #run()} method.
+     */
+    protected Thread sessionThread;
+    protected final boolean maintainStateAfterException;
+    protected final AtomicReference<CloseReason> closeReason = new AtomicReference<>();
+    protected final GraphManager graphManager;
+    protected final ConcurrentMap<String, Session> sessions;
+    protected final Set<String> aliasesUsedBySession = new HashSet<>();
+
+    /**
+     * The reason that a particular session closed. The reason for the close is generally not important as a
+     * final disposition for the {@link Session} instance and is more useful in aiding flow control during the
+     * close process.
+     */
+    protected enum CloseReason {
+
+        /**
+         * The session exits in a fashion that did not precipitate from some form of interruption, timeout or
+         * exception, i.e. it is simply allowed to process to an exit through its normal execution flow. This status
+         * may or may not be possible given the context of the implementation. For example, a {@link MultiTaskSession}
+         * needs to be interrupted to stop processing.
+         */
+        EXIT_PROCESSING,
+
+        /**
+         * The session was interrupted by the channel closing, which can be something initiated by closing the
+         * {@link Client} or might be triggered by the server. This may not be considered an error situation and
+         * depending on context, might be similar to a {@link #EXIT_PROCESSING} termination.
+         */
+        CHANNEL_CLOSED,
+
+        /**
+         * The session encountered an exception related to execution like a script error, traversal iteration problem,
+         * serialization issue, etc.
+         */
+        PROCESSING_EXCEPTION,
+
+        /**
+         * The session was interrupted by the session lifetime timeout.
+         */
+        SESSION_TIMEOUT,
+
+        /**
+         * The session was interrupted by the request timeout.
+         */
+        REQUEST_TIMEOUT
+    }
+
+    AbstractSession(final SessionTask sessionTask, final String sessionId,
+                    final boolean transactionManaged,
+                    final ConcurrentMap<String, Session> sessions) {
+        // this only applies to sessions
+        this.maintainStateAfterException = (boolean) sessionTask.getRequestMessage().
+                optionalArgs(Tokens.ARGS_MAINTAIN_STATE_AFTER_EXCEPTION).orElse(false);
+        this.sessionIdOnRequest = sessionTask.getRequestMessage().optionalArgs(Tokens.ARGS_SESSION).isPresent();
+        this.transactionManaged = transactionManaged;
+        this.sessionId = sessionId;
+        this.initialChannel = sessionTask.getChannelHandlerContext().channel();
+
+        // close session if the channel closes to cleanup and close transactions
+        this.initialChannel.closeFuture().addListener(f -> {
+            if (closeReason.compareAndSet(null, CloseReason.CHANNEL_CLOSED)) {
+                close();
+            }
+        });
+        this.sessions = sessions;
+        this.graphManager = sessionTask.getGraphManager();
+    }
+
+    protected synchronized void cancel(final boolean mayInterruptIfRunning) {
+        final FutureTask<?> sf = (FutureTask) sessionFuture.get();
+        if (sf != null && !sf.isDone()) {
+            sf.cancel(mayInterruptIfRunning);
+        }
+    }
+
+    public boolean isTransactionManaged() {
+        return transactionManaged;
+    }
+
+    @Override
+    public String getSessionId() {
+        return sessionId;
+    }
+
+    public boolean isBoundTo(final Channel channel) {
+        return channel == initialChannel;
+    }
+
+    public long getActualTimeoutLengthWhenClosed() {
+        return actualTimeoutLengthWhenClosed;
+    }
+
+    public Optional<CloseReason> getCloseReason() {
+        return Optional.ofNullable(closeReason.get());
+    }
+
+    /**
+     * Gets the script engine from the cached one in the {@link GremlinExecutor}.
+     */
+    public GremlinScriptEngine getScriptEngine(final SessionTask sessionTask, final String language) {
+        return sessionTask.getGremlinExecutor().getScriptEngineManager().getEngineByName(language);
+    }
+
+    @Override
+    public void setSessionCancelFuture(final ScheduledFuture<?> f) {
+        if (!sessionCancelFuture.compareAndSet(null, f))
+            throw new IllegalStateException("Session cancellation future is already set");
+    }
+
+    @Override
+    public void setSessionFuture(final Future<?> f) {
+        if (!sessionFuture.compareAndSet(null, f))
+            throw new IllegalStateException("Session future is already set");
+    }
+
+    @Override
+    public synchronized void triggerTimeout(final long timeout, final boolean causedBySession) {
+        // triggering timeout triggers the stop of the session which will end in close()
+        // for final cleanup
+        final Future<?> f = sessionFuture.get();
+        if (f != null && !f.isDone()) {
+            if (closeReason.compareAndSet(null, causedBySession ? CloseReason.SESSION_TIMEOUT : CloseReason.REQUEST_TIMEOUT)) {
+                actualTimeoutLengthWhenClosed = timeout;
+
+                // if caused by a session timeout for a MultiTaskSession OR if it is a request timeout for a
+                // SingleTaskSession request then we can just straight cancel() the session instance
+                if (causedBySession || !sessionIdOnRequest)
+                    cancel(true);
+                else {
+                    // in both MultiTaskSession and SingleTaskSession the thread gets set immediately at the start
+                    // of run() as it should (though "single" has little need for it). As triggerTimeout() for a
+                    // request MultiTaskSession can only be called AFTER we are deep in the run() there should be
+                    // no chance of race conditions or situations where the sessionThread is null at this point.
+                    if (sessionThread != null) {
+                        sessionThread.interrupt();
+                    } else {
+                        logger.debug("{} is a {} which is not interruptable as the thread running the session has not " +
+                                        "been set - please check the implementation if this is not desirable",
+                                sessionId, this.getClass().getSimpleName());
+                    }
+                }
+            }
+        }
+    }
+
+    protected void process(final SessionTask sessionTask) throws SessionException {
+        final RequestMessage msg = sessionTask.getRequestMessage();
+        final Map<String, Object> args = msg.getArgs();
+        final Object gremlinToExecute = args.get(Tokens.ARGS_GREMLIN);
+
+        // for strict transactions track the aliases used so that we can commit them and only them on close()
+        if (sessionTask.getSettings().strictTransactionManagement)
+            msg.optionalArgs(Tokens.ARGS_ALIASES).ifPresent(m -> aliasesUsedBySession.addAll(((Map<String,String>) m).values()));
+
+        final Timer.Context timer = getMetricsTimer(sessionTask);
+        try {
+            // itty is optional as Bytecode could be a "graph operation" rather than a Traversal. graph operations
+            // don't need to be iterated and handle their own lifecycle
+            final Optional<Iterator<?>> itty = gremlinToExecute instanceof Bytecode ?
+                    fromBytecode(sessionTask, (Bytecode) gremlinToExecute) :
+                    Optional.of(fromScript(sessionTask, (String) gremlinToExecute));
+
+            processAuditLog(sessionTask.getSettings(), sessionTask.getChannelHandlerContext(), gremlinToExecute);
+
+            if (itty.isPresent())
+                handleIterator(sessionTask, itty.get());
+        } catch (Exception ex) {
+            handleException(sessionTask, ex);
+        } finally {
+            timer.stop();
+        }
+    }
+
+    protected void handleException(final SessionTask sessionTask, final Throwable t) throws SessionException {
+        if (t instanceof SessionException) throw (SessionException) t;
+
+        final Optional<Throwable> possibleTemporaryException = determineIfTemporaryException(t);
+        if (possibleTemporaryException.isPresent()) {
+            final Throwable temporaryException = possibleTemporaryException.get();
+            throw new SessionException(temporaryException.getMessage(), t,
+                    ResponseMessage.build(sessionTask.getRequestMessage())
+                            .code(ResponseStatusCode.SERVER_ERROR_TEMPORARY)
+                            .statusMessage(temporaryException.getMessage())
+                            .statusAttributeException(temporaryException).create());
+        }
+
+        final Throwable root = ExceptionUtils.getRootCause(t);
+
+        if (root instanceof TimedInterruptTimeoutException) {
+            // occurs when the TimedInterruptCustomizerProvider is in play
+            final String msg = String.format("A timeout occurred within the script during evaluation of [%s] - consider increasing the limit given to TimedInterruptCustomizerProvider",
+                    sessionTask.getRequestMessage().getRequestId());
+            throw new SessionException(msg, root, ResponseMessage.build(sessionTask.getRequestMessage())
+                    .code(ResponseStatusCode.SERVER_ERROR_TIMEOUT)
+                    .statusMessage("Timeout during script evaluation triggered by TimedInterruptCustomizerProvider")
+                    .create());
+        }
+
+        if (root instanceof TimeoutException) {
+            final String errorMessage = String.format("Script evaluation exceeded the configured threshold for request [%s]",
+                    sessionTask.getRequestMessage().getRequestId());
+            throw new SessionException(errorMessage, root, ResponseMessage.build(sessionTask.getRequestMessage())
+                    .code(ResponseStatusCode.SERVER_ERROR_TIMEOUT)
+                    .statusMessage(t.getMessage())
+                    .create());
+        }
+
+        if (root instanceof InterruptedException ||
+                root instanceof TraversalInterruptedException ||
+                root instanceof InterruptedIOException) {
+            String msg = "Processing interrupted but the reason why was not known";
+            switch (closeReason.get()) {
+                case CHANNEL_CLOSED:
+                    msg = "Processing interrupted because the channel was closed";
+                    break;
+                case SESSION_TIMEOUT:
+                    msg = String.format("Session closed - %s - sessionLifetimeTimeout of %s ms exceeded", sessionId, actualTimeoutLengthWhenClosed);
+                    break;
+                case REQUEST_TIMEOUT:
+                    msg = String.format("Evaluation exceeded timeout threshold of %s ms", actualTimeoutLengthWhenClosed);
+                    break;
+            }
+            final ResponseStatusCode code = closeReason.get() == CloseReason.SESSION_TIMEOUT || closeReason.get() == CloseReason.REQUEST_TIMEOUT ?
+                    ResponseStatusCode.SERVER_ERROR_TIMEOUT : ResponseStatusCode.SERVER_ERROR;
+            throw new SessionException(msg, root, ResponseMessage.build(sessionTask.getRequestMessage())
+                    .code(code)
+                    .statusMessage(msg).create());
+        }
+
+        if (root instanceof MultipleCompilationErrorsException && root.getMessage().contains("Method too large") &&
+                ((MultipleCompilationErrorsException) root).getErrorCollector().getErrorCount() == 1) {
+            final String errorMessage = String.format("The Gremlin statement that was submitted exceeds the maximum compilation size allowed by the JVM, please split it into multiple smaller statements - %s", trimMessage(sessionTask.getRequestMessage()));
+            logger.warn(errorMessage);
+            throw new SessionException(errorMessage, root, ResponseMessage.build(sessionTask.getRequestMessage())
+                    .code(ResponseStatusCode.SERVER_ERROR_EVALUATION)
+                    .statusMessage(errorMessage)
+                    .statusAttributeException(root).create());
+        }
+
+        // GroovyRuntimeException will hit a pretty wide range of eval type errors, like MissingPropertyException,
+        // CompilationFailedException, MissingMethodException, etc. If more specific handling is required then
+        // try to catch it earlier above.
+        if (root instanceof GroovyRuntimeException ||
+                root instanceof VerificationException ||
+                root instanceof ScriptException) {
+            throw new SessionException(root.getMessage(), root, ResponseMessage.build(sessionTask.getRequestMessage())
+                    .code(ResponseStatusCode.SERVER_ERROR_EVALUATION)
+                    .statusMessage(root.getMessage())
+                    .statusAttributeException(root).create());
+        }
+
+        throw new SessionException(root.getClass().getSimpleName() + ": " + root.getMessage(), root,
+                ResponseMessage.build(sessionTask.getRequestMessage())
+                        .code(ResponseStatusCode.SERVER_ERROR)
+                        .statusAttributeException(root)
+                        .statusMessage(root.getMessage()).create());
+    }
+
+    /**
+     * Used to decrease the size of a Gremlin script that triggered a "method too large" exception so that it
+     * doesn't log a massive text string nor return a large error message.
+     */
+    private RequestMessage trimMessage(final RequestMessage msg) {
+        final RequestMessage trimmedMsg = RequestMessage.from(msg).create();
+        if (trimmedMsg.getArgs().containsKey(Tokens.ARGS_GREMLIN))
+            trimmedMsg.getArgs().put(Tokens.ARGS_GREMLIN, trimmedMsg.getArgs().get(Tokens.ARGS_GREMLIN).toString().substring(0, 1021) + "...");
+
+        return trimmedMsg;
+    }
+
+    /**
+     * Check if any exception in the chain is TemporaryException then we should respond with the right error code so
+     * that the client knows to retry.
+     */
+    protected Optional<Throwable> determineIfTemporaryException(final Throwable ex) {
+        return Stream.of(ExceptionUtils.getThrowables(ex)).
+                filter(i -> i instanceof TemporaryException).findFirst();
+    }
+
+    /**
+     * Removes the session from the session list and cancels the future that manages the lifetime of the session.
+     */
+    @Override
+    public synchronized void close() {
+        // already closing/closed
+        if (!sessions.containsKey(sessionId)) return;
+
+        sessions.remove(sessionId);
+
+        if (sessionCancelFuture.get() != null) {
+            final ScheduledFuture<?> f = sessionCancelFuture.get();
+            if (!f.isDone()) f.cancel(true);
+        }
+    }
+
+    /**
+     * Constructs an {@code Iterator} from the results of a script evaluation provided in the {@link SessionTask}.
+     *
+     * @param sessionTask The session task which can be used as a context in constructing the {@code Iterator}
+     * @param script The script extracted by the calling method from the {@code sessionTask}
+     */
+    protected Iterator<?> fromScript(final SessionTask sessionTask, final String script) throws Exception {
+        final RequestMessage msg = sessionTask.getRequestMessage();
+        final Map<String, Object> args = msg.getArgs();
+        final String language = args.containsKey(Tokens.ARGS_LANGUAGE) ? (String) args.get(Tokens.ARGS_LANGUAGE) : "gremlin-groovy";
+        return IteratorUtils.asIterator(getScriptEngine(sessionTask, language).eval(
+                script, mergeBindingsFromRequest(sessionTask, getWorkerBindings())));
+    }
+
+    /**
+     * Constructs an {@code Iterator} from {@link Bytecode} provided in the {@link SessionTask}. If the {@link Bytecode}
+     * is found to evalute to a {@link GraphOp} then it is processed and an empty {@code Optional} is returned.
+     *
+     * @param sessionTask The session task which can be used as a context in constructing the {@code Iterator}
+     * @param bytecode The {@link Bytecode} extracted by the calling method from the {@code sessionTask}
+     */
+    protected Optional<Iterator<?>> fromBytecode(final SessionTask sessionTask, final Bytecode bytecode) throws Exception {
+        final RequestMessage msg = sessionTask.getRequestMessage();
+
+        final Traversal.Admin<?, ?> traversal;
+        final Map<String, String> aliases = (Map<String, String>) msg.optionalArgs(Tokens.ARGS_ALIASES).get();
+        final GraphManager graphManager = sessionTask.getGraphManager();
+        final String traversalSourceName = aliases.entrySet().iterator().next().getValue();
+        final TraversalSource g = graphManager.getTraversalSource(traversalSourceName);
+
+        // handle bytecode based graph operations like commit/rollback commands
+        if (BytecodeHelper.isGraphOperation(bytecode)) {
+            handleGraphOperation(sessionTask, bytecode, g.getGraph());
+            return Optional.empty();
+        } else {
+
+            final Optional<String> lambdaLanguage = BytecodeHelper.getLambdaLanguage(bytecode);
+            if (!lambdaLanguage.isPresent())
+                traversal = JavaTranslator.of(g).translate(bytecode);
+            else {
+                final SimpleBindings bindings = new SimpleBindings();
+                bindings.put(traversalSourceName, g);
+                traversal = sessionTask.getGremlinExecutor().getScriptEngineManager().
+                        getEngineByName(lambdaLanguage.get()).eval(bytecode, bindings, traversalSourceName);
+            }
+
+            // compile the traversal - without it getEndStep() has nothing in it
+            traversal.applyStrategies();
+
+            return Optional.of(new TraverserIterator(traversal));
+        }
+    }
+
+    protected Bindings getWorkerBindings() throws SessionException {
+        return new SimpleBindings(graphManager.getAsBindings());
+    }
+
+    protected Bindings mergeBindingsFromRequest(final SessionTask sessionTask, final Bindings bindings) throws SessionException {
+        // alias any global bindings to a different variable.
+        final RequestMessage msg = sessionTask.getRequestMessage();
+        if (msg.getArgs().containsKey(Tokens.ARGS_ALIASES)) {
+            final Map<String, String> aliases = (Map<String, String>) msg.getArgs().get(Tokens.ARGS_ALIASES);
+            for (Map.Entry<String,String> aliasKv : aliases.entrySet()) {
+                boolean found = false;
+
+                // first check if the alias refers to a Graph instance
+                final Graph graph = sessionTask.getGraphManager().getGraph(aliasKv.getValue());
+                if (null != graph) {
+                    bindings.put(aliasKv.getKey(), graph);
+                    found = true;
+                }
+
+                // if the alias wasn't found as a Graph then perhaps it is a TraversalSource - it needs to be
+                // something
+                if (!found) {
+                    final TraversalSource ts = sessionTask.getGraphManager().getTraversalSource(aliasKv.getValue());
+                    if (null != ts) {
+                        bindings.put(aliasKv.getKey(), ts);
+                        found = true;
+                    }
+                }
+
+                // this validation is important to calls to GraphManager.commit() and rollback() as they both
+                // expect that the aliases supplied are valid
+                if (!found) {
+                    final String error = String.format("Could not alias [%s] to [%s] as [%s] not in the Graph or TraversalSource global bindings",
+                            aliasKv.getKey(), aliasKv.getValue(), aliasKv.getValue());
+                    throw new SessionException(error, ResponseMessage.build(msg)
+                            .code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(error).create());
+                }
+            }
+        } else {
+            // there's no bindings so determine if that's ok with Gremlin Server
+            if (sessionTask.getSettings().strictTransactionManagement) {
+                final String error = "Gremlin Server is configured with strictTransactionManagement as 'true' - the 'aliases' arguments must be provided";
+                throw new SessionException(error, ResponseMessage.build(msg)
+                        .code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(error).create());
+            }
+        }
+
+        // add any bindings to override any other supplied
+        Optional.ofNullable((Map<String, Object>) msg.getArgs().get(Tokens.ARGS_BINDINGS)).ifPresent(bindings::putAll);
+        return bindings;
+    }
+
+    /**
+     * Provides a generic way of iterating a result set back to the client.
+     *
+     * @param sessionTask The Gremlin Server {@link SessionTask} object containing settings, request message, etc.
+     * @param itty The result to iterator
+     */
+    protected void handleIterator(final SessionTask sessionTask, final Iterator<?> itty) throws InterruptedException {
+        final ChannelHandlerContext nettyContext = sessionTask.getChannelHandlerContext();
+        final RequestMessage msg = sessionTask.getRequestMessage();
+        final Settings settings = sessionTask.getSettings();
+        boolean warnOnce = false;
+
+        // sessionless requests are always transaction managed, but in-session requests are configurable.
+        final boolean managedTransactionsForRequest = transactionManaged ?
+                true : (Boolean) msg.getArgs().getOrDefault(Tokens.ARGS_MANAGE_TRANSACTION, false);
+
+        // we have an empty iterator - happens on stuff like: g.V().iterate()
+        if (!itty.hasNext()) {
+            final Map<String, Object> attributes = generateStatusAttributes(sessionTask,ResponseStatusCode.NO_CONTENT, itty);
+            // as there is nothing left to iterate if we are transaction managed then we should execute a
+            // commit here before we send back a NO_CONTENT which implies success
+            if (managedTransactionsForRequest)
+                closeTransaction(sessionTask, Transaction.Status.COMMIT);
+
+            sessionTask.writeAndFlush(ResponseMessage.build(msg)
+                    .code(ResponseStatusCode.NO_CONTENT)
+                    .statusAttributes(attributes)
+                    .create());
+            return;
+        }
+
+        // the batch size can be overridden by the request
+        final int resultIterationBatchSize = (Integer) msg.optionalArgs(Tokens.ARGS_BATCH_SIZE)
+                .orElse(settings.resultIterationBatchSize);
+        List<Object> aggregate = new ArrayList<>(resultIterationBatchSize);
+
+        // use an external control to manage the loop as opposed to just checking hasNext() in the while.  this
+        // prevent situations where auto transactions create a new transaction after calls to commit() withing
+        // the loop on calls to hasNext().
+        boolean hasMore = itty.hasNext();
+
+        while (hasMore) {
+            if (Thread.interrupted()) throw new InterruptedException();
+
+            // check if an implementation needs to force flush the aggregated results before the iteration batch
+            // size is reached.
+            // todo: what implementation does this?! can we kill it going forward - seems always false
+            // final boolean forceFlush = isForceFlushed(nettyContext, msg, itty);
+            final boolean forceFlush = false;
+
+            // have to check the aggregate size because it is possible that the channel is not writeable (below)
+            // so iterating next() if the message is not written and flushed would bump the aggregate size beyond
+            // the expected resultIterationBatchSize.  Total serialization time for the response remains in
+            // effect so if the client is "slow" it may simply timeout.
+            //
+            // there is a need to check hasNext() on the iterator because if the channel is not writeable the
+            // previous pass through the while loop will have next()'d the iterator and if it is "done" then a
+            // NoSuchElementException will raise its head. also need a check to ensure that this iteration doesn't
+            // require a forced flush which can be forced by sub-classes.
+            //
+            // this could be placed inside the isWriteable() portion of the if-then below but it seems better to
+            // allow iteration to continue into a batch if that is possible rather than just doing nothing at all
+            // while waiting for the client to catch up
+            if (aggregate.size() < resultIterationBatchSize && itty.hasNext() && !forceFlush) aggregate.add(itty.next());
+
+            // send back a page of results if batch size is met or if it's the end of the results being iterated.
+            // also check writeability of the channel to prevent OOME for slow clients.
+            //
+            // clients might decide to close the Netty channel to the server with a CloseWebsocketFrame after errors
+            // like CorruptedFrameException. On the server, although the channel gets closed, there might be some
+            // executor threads waiting for watermark to clear which will not clear in these cases since client has
+            // already given up on these requests. This leads to these executors waiting for the client to consume
+            // results till the timeout. checking for isActive() should help prevent that.
+            if (nettyContext.channel().isActive() && nettyContext.channel().isWritable()) {
+                if (forceFlush || aggregate.size() == resultIterationBatchSize || !itty.hasNext()) {
+                    final ResponseStatusCode code = itty.hasNext() ? ResponseStatusCode.PARTIAL_CONTENT : ResponseStatusCode.SUCCESS;
+                    Frame frame = null;
+                    try {
+                        frame = makeFrame(sessionTask, aggregate, code, itty);
+                    } catch (Exception ex) {
+                        // a frame may use a Bytebuf which is a countable release - if it does not get written
+                        // downstream it needs to be released here
+                        if (frame != null) frame.tryRelease();
+
+                        // exception is handled in makeFrame() - serialization error gets written back to driver
+                        // at that point
+                        if (managedTransactionsForRequest)
+                            closeTransaction(sessionTask, Transaction.Status.ROLLBACK);
+                        break;
+                    }
+
+                    // track whether there is anything left in the iterator because it needs to be accessed after
+                    // the transaction could be closed - in that case a call to hasNext() could open a new transaction
+                    // unintentionally
+                    final boolean moreInIterator = itty.hasNext();
+
+                    try {
+                        // only need to reset the aggregation list if there's more stuff to write
+                        if (moreInIterator)
+                            aggregate = new ArrayList<>(resultIterationBatchSize);
+                        else {
+                            // iteration and serialization are both complete which means this finished successfully. note that
+                            // errors internal to script eval or timeout will rollback given GremlinServer's global configurations.
+                            // local errors will get rolledback below because the exceptions aren't thrown in those cases to be
+                            // caught by the GremlinExecutor for global rollback logic. this only needs to be committed if
+                            // there are no more items to iterate and serialization is complete
+                            if (managedTransactionsForRequest)
+                                closeTransaction(sessionTask, Transaction.Status.COMMIT);
+
+                            // exit the result iteration loop as there are no more results left.  using this external control
+                            // because of the above commit.  some graphs may open a new transaction on the call to
+                            // hasNext()
+                            hasMore = false;
+                        }
+                    } catch (Exception ex) {
+                        // a frame may use a Bytebuf which is a countable release - if it does not get written
+                        // downstream it needs to be released here
+                        if (frame != null) frame.tryRelease();
+                        throw ex;
+                    }
+
+                    if (!moreInIterator) iterateComplete(sessionTask, itty);
+
+                    // the flush is called after the commit has potentially occurred.  in this way, if a commit was
+                    // required then it will be 100% complete before the client receives it. the "frame" at this point
+                    // should have completely detached objects from the transaction (i.e. serialization has occurred)
+                    // so a new one should not be opened on the flush down the netty pipeline
+                    sessionTask.writeAndFlush(code, frame);
+                }
+            } else {
+                // don't keep triggering this warning over and over again for the same request
+                if (!warnOnce) {
+                    logger.warn("Pausing response writing as writeBufferHighWaterMark exceeded on {} - writing will continue once client has caught up", msg);
+                    warnOnce = true;
+                }
+
+                // since the client is lagging we can hold here for a period of time for the client to catch up.
+                // this isn't blocking the IO thread - just a worker.
+                TimeUnit.MILLISECONDS.sleep(10);
+            }
+        }
+    }
+
+    /**
+     * If {@link Bytecode} is detected to contain a {@link GraphOp} then it gets processed by this method.
+     */
+    protected void handleGraphOperation(final SessionTask sessionTask, final Bytecode bytecode, final Graph graph) throws Exception {
+        final RequestMessage msg = sessionTask.getRequestMessage();
+        if (graph.features().graph().supportsTransactions()) {
+            if (TX_COMMIT.equals(bytecode) || TX_ROLLBACK.equals(bytecode)) {
+                final boolean commit = TX_COMMIT.equals(bytecode);
+                closeTransaction(sessionTask, commit ? Transaction.Status.COMMIT : Transaction.Status.ROLLBACK);
+
+                // write back a no-op for success
+                final Map<String, Object> attributes = generateStatusAttributes(sessionTask,
+                        ResponseStatusCode.NO_CONTENT, Collections.emptyIterator());
+                sessionTask.writeAndFlush(ResponseMessage.build(msg)
+                            .code(ResponseStatusCode.NO_CONTENT)
+                            .statusAttributes(attributes)
+                            .create());
+            } else {
+                throw new IllegalStateException(String.format(
+                        "Bytecode in request is not a recognized graph operation: %s", bytecode.toString()));
+            }
+        }
+    }
+
+    /**
+     * Called when iteration within {@link #handleIterator(SessionTask, Iterator)} is on its final pass and the final
+     * frame is about to be sent back to the client. This method only gets called on successful iteration of the
+     * entire result.
+     */
+    protected void iterateComplete(final SessionTask sessionTask, final Iterator<?> itty) {
+        // do nothing by default
+    }
+
+    /**
+     * Generates response status meta-data to put on a {@link ResponseMessage}.
+     *
+     * @param itty a reference to the current {@link Iterator} of results - it is not meant to be forwarded in
+     *             this method
+     */
+    protected Map<String, Object> generateStatusAttributes(final SessionTask sessionTask,
+                                                           final ResponseStatusCode code, final Iterator<?> itty) {
+        // only return server metadata on the last message
+        if (itty.hasNext()) return Collections.emptyMap();
+
+        final Map<String, Object> metaData = new HashMap<>();
+        metaData.put(Tokens.ARGS_HOST, sessionTask.getChannelHandlerContext().channel().remoteAddress().toString());
+
+        return metaData;
+    }
+
+    /**
+     * Generates response result meta-data to put on a {@link ResponseMessage}.
+     *
+     * @param itty a reference to the current {@link Iterator} of results - it is not meant to be forwarded in
+     *             this method
+     */
+    protected Map<String, Object> generateResponseMetaData(final SessionTask sessionTask,
+                                                           final ResponseStatusCode code, final Iterator<?> itty) {
+        return Collections.emptyMap();
+    }
+
+    protected Frame makeFrame(final SessionTask sessionTask, final List<Object> aggregate,
+                              final ResponseStatusCode code, final Iterator<?> itty) throws Exception {
+        final RequestMessage msg = sessionTask.getRequestMessage();
+        final ChannelHandlerContext nettyContext = sessionTask.getChannelHandlerContext();
+        final MessageSerializer serializer = nettyContext.channel().attr(StateKey.SERIALIZER).get();
+        final boolean useBinary = nettyContext.channel().attr(StateKey.USE_BINARY).get();
+
+        final Map<String, Object> responseMetaData = generateResponseMetaData(sessionTask, code, itty);
+        final Map<String, Object> statusAttributes = generateStatusAttributes(sessionTask, code, itty);
+        try {
+            if (useBinary) {
+                return new Frame(serializer.serializeResponseAsBinary(ResponseMessage.build(msg)
+                        .code(code)
+                        .statusAttributes(statusAttributes)
+                        .responseMetaData(responseMetaData)
+                        .result(aggregate).create(), nettyContext.alloc()));
+            } else {
+                // the expectation is that the GremlinTextRequestDecoder will have placed a MessageTextSerializer
+                // instance on the channel.
+                final MessageTextSerializer textSerializer = (MessageTextSerializer) serializer;
+                return new Frame(textSerializer.serializeResponseAsString(ResponseMessage.build(msg)
+                        .code(code)
+                        .statusAttributes(statusAttributes)
+                        .responseMetaData(responseMetaData)
+                        .result(aggregate).create()));
+            }
+        } catch (Exception ex) {
+            logger.warn("The result [{}] in the request {} could not be serialized and returned.", aggregate, msg.getRequestId(), ex);
+            final String errorMessage = String.format("Error during serialization: %s", ExceptionHelper.getMessageFromExceptionOrCause(ex));
+            final ResponseMessage error = ResponseMessage.build(msg.getRequestId())
+                    .statusMessage(errorMessage)
+                    .statusAttributeException(ex)
+                    .code(ResponseStatusCode.SERVER_ERROR_SERIALIZATION).create();
+            sessionTask.writeAndFlush(error);
+            throw ex;
+        }
+    }
+
+    /**
+     * Called right before a transaction starts within {@link #run()}. The default implementation checks for open
+     * transactions and throws an exception if it finds any and generally assumes auto-transactions are enabled on
+     * graphs (i.e. transaction automatically start on read/write).
+     * <p/>
+     * Providers who do not follow these sorts of transaction semantics should provide an override to this method.
+     */
+    protected void startTransaction(final SessionTask sessionTask) {
+        if (graphManager.hasAnyOpenTransactions()) {
+            // logger and handling in calling method
+            throw new IllegalStateException(String.format(
+                    "Attempted to start transaction for %s but the transaction was already open",
+                    sessionTask.getRequestMessage().getRequestId()));
+        }
+    }
+
+    /**
+     * Close the transaction without a {@link SessionTask} which supplies {@code null} to that argument for
+     * {@link #closeTransaction(SessionTask, Transaction.Status)}. This method is idempotent.
+     */
+    protected void closeTransaction(final Transaction.Status status) {
+        closeTransaction(null, status);
+    }
+
+    /**
+     * Tries to close the transaction but will catch exceptions and log them. This method is idempotent.
+     */
+    protected void closeTransactionSafely(final Transaction.Status status) {
+        closeTransactionSafely(null, status);
+    }
+
+    /**
+     * Tries to close the transaction but will catch exceptions and log them. This method is idempotent.
+     */
+    protected void closeTransactionSafely(final SessionTask sessionTask, final Transaction.Status status) {
+        try {
+            closeTransaction(sessionTask, status);
+        } catch (Exception ex) {
+            logger.error("Failed to close transaction", ex);
+        }
+    }
+
+    private void processAuditLog(final Settings settings, final ChannelHandlerContext ctx, final Object gremlinToExecute) {
+        if (settings.enableAuditLog) {
+            AuthenticatedUser user = ctx.channel().attr(StateKey.AUTHENTICATED_USER).get();
+            if (null == user) {    // This is expected when using the AllowAllAuthenticator
+                user = AuthenticatedUser.ANONYMOUS_USER;
+            }
+            String address = ctx.channel().remoteAddress().toString();
+            if (address.startsWith("/") && address.length() > 1) address = address.substring(1);
+            auditLogger.info("User {} with address {} requested: {}", user.getName(), address, gremlinToExecute);
+        }
+
+        if (settings.authentication.enableAuditLog) {
+            String address = ctx.channel().remoteAddress().toString();
+            if (address.startsWith("/") && address.length() > 1) address = address.substring(1);
+            auditLogger.info("User with address {} requested: {}", address, gremlinToExecute);
+        }
+    }
+
+    /**
+     * Closes a transaction with commit or rollback. Strict transaction management settings are observed when
+     * configured as such in {@link Settings#strictTransactionManagement} and when aliases are present on the
+     * request in the current {@link SessionTask}. If the supplied {@link SessionTask} is {@code null} then "strict" is
+     * bypassed so this form must be called with care. Bypassing is often useful to ensure that all transactions
+     * are cleaned up when multiple graphs are referenced. Prefer calling {@link #closeTransaction(Transaction.Status)}
+     * in this case instead. This method is idempotent.
+     */
+    protected void closeTransaction(final SessionTask sessionTask, final Transaction.Status status) {
+        if (status != Transaction.Status.COMMIT && status != Transaction.Status.ROLLBACK)
+            throw new IllegalStateException(String.format("Transaction.Status not supported: %s", status));
+
+        final boolean commit = status == Transaction.Status.COMMIT;
+        final boolean strict = sessionTask != null && sessionTask.getSettings().strictTransactionManagement;
+
+        if (strict) {
+            if (commit)
+                graphManager.commit(new HashSet<>(aliasesUsedBySession));
+            else
+                graphManager.rollback(new HashSet<>(aliasesUsedBySession));
+        } else {
+            if (commit)
+                graphManager.commitAll();
+            else
+                graphManager.rollbackAll();
+        }
+    }
+
+    private Timer.Context getMetricsTimer(final SessionTask sessionTask) {
+        // getting something other than bytecode or script at this point is unlikely as earlier validations
+        // should have picked this up.
+        switch (sessionTask.getRequestContentType()) {
+            case BYTECODE:
+                return Session.traversalOpTimer.time();
+            case SCRIPT:
+                return Session.evalOpTimer.time();
+            default:
+                throw new IllegalStateException("Unrecognized content of the 'gremlin' argument in the request");
+        }
+    }
+}
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/GremlinResponseFrameEncoder.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/GremlinResponseFrameEncoder.java
index 3aa8c36..6020b36 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/GremlinResponseFrameEncoder.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/GremlinResponseFrameEncoder.java
@@ -52,7 +52,7 @@
 
     @Override
     protected void encode(final ChannelHandlerContext ctx, final ResponseMessage o, final List<Object> objects) throws Exception {
-        final MessageSerializer serializer = ctx.channel().attr(StateKey.SERIALIZER).get();
+        final MessageSerializer<?> serializer = ctx.channel().attr(StateKey.SERIALIZER).get();
         final boolean useBinary = ctx.channel().attr(StateKey.USE_BINARY).get();
         final Session session = ctx.channel().attr(StateKey.SESSION).get();
 
@@ -77,7 +77,7 @@
             } else {
                 // the expectation is that the GremlinTextRequestDecoder will have placed a MessageTextSerializer
                 // instance on the channel.
-                final MessageTextSerializer textSerializer = (MessageTextSerializer) serializer;
+                final MessageTextSerializer<?> textSerializer = (MessageTextSerializer<?>) serializer;
 
                 final Frame serialized;
 
@@ -101,7 +101,7 @@
             if (useBinary) {
                 objects.add(serializer.serializeResponseAsBinary(error, ctx.alloc()));
             } else {
-                final MessageTextSerializer textSerializer = (MessageTextSerializer) serializer;
+                final MessageTextSerializer<?> textSerializer = (MessageTextSerializer<?>) serializer;
                 objects.add(textSerializer.serializeResponseAsString(error));
             }
         }
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpBasicAuthenticationHandler.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpBasicAuthenticationHandler.java
index 537b1d4..a050ab0 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpBasicAuthenticationHandler.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpBasicAuthenticationHandler.java
@@ -20,14 +20,15 @@
 
 import io.netty.channel.ChannelFutureListener;
 import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.ChannelInboundHandlerAdapter;
 import io.netty.handler.codec.http.DefaultFullHttpResponse;
 import io.netty.handler.codec.http.FullHttpMessage;
 import io.netty.util.ReferenceCountUtil;
 import org.apache.tinkerpop.gremlin.server.GremlinServer;
 import org.apache.tinkerpop.gremlin.server.Settings;
+import org.apache.tinkerpop.gremlin.server.auth.AuthenticatedUser;
 import org.apache.tinkerpop.gremlin.server.auth.AuthenticationException;
 import org.apache.tinkerpop.gremlin.server.auth.Authenticator;
+import org.apache.tinkerpop.gremlin.server.authz.Authorizer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -50,14 +51,21 @@
 public class HttpBasicAuthenticationHandler extends AbstractAuthenticationHandler {
     private static final Logger logger = LoggerFactory.getLogger(HttpBasicAuthenticationHandler.class);
     private static final Logger auditLogger = LoggerFactory.getLogger(GremlinServer.AUDIT_LOGGER_NAME);
-    private final Settings.AuthenticationSettings authenticationSettings;
+    private final Settings settings;
 
     private final Base64.Decoder decoder = Base64.getUrlDecoder();
 
-    public HttpBasicAuthenticationHandler(final Authenticator authenticator,
-                                          final Settings.AuthenticationSettings authenticationSettings) {
-        super(authenticator);
-        this.authenticationSettings = authenticationSettings;
+    /**
+     * @deprecated As of release 3.5.0, replaced by {@link #HttpBasicAuthenticationHandler(Authenticator, Authorizer, Settings)}.
+     */
+    @Deprecated
+    public HttpBasicAuthenticationHandler(final Authenticator authenticator, final Settings settings) {
+        this(authenticator, null, settings);
+    }
+
+    public HttpBasicAuthenticationHandler(final Authenticator authenticator, final Authorizer authorizer, final Settings settings) {
+        super(authenticator, authorizer);
+        this.settings = settings;
     }
 
     @Override
@@ -103,11 +111,11 @@
             credentials.put(PROPERTY_ADDRESS, address);
 
             try {
-                authenticator.authenticate(credentials);
+                final AuthenticatedUser user = authenticator.authenticate(credentials);
+                ctx.channel().attr(StateKey.AUTHENTICATED_USER).set(user);
                 ctx.fireChannelRead(request);
-
                 // User name logged with the remote socket address and authenticator classname for audit logging
-                if (authenticationSettings.enableAuditLog) {
+                if (settings.enableAuditLog || settings.authentication.enableAuditLog) {
                     final String[] authClassParts = authenticator.getClass().toString().split("[.]");
                     auditLogger.info("User {} with address {} authenticated by {}",
                             credentials.get(PROPERTY_USERNAME), address, authClassParts[authClassParts.length - 1]);
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpBasicAuthorizationHandler.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpBasicAuthorizationHandler.java
new file mode 100644
index 0000000..0951a5d
--- /dev/null
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpBasicAuthorizationHandler.java
@@ -0,0 +1,110 @@
+/*
+ * 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.server.handler;
+
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import io.netty.handler.codec.http.FullHttpMessage;
+import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.codec.http.HttpUtil;
+import io.netty.util.ReferenceCountUtil;
+import org.apache.tinkerpop.gremlin.driver.Tokens;
+import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
+import org.apache.tinkerpop.gremlin.server.GremlinServer;
+import org.apache.tinkerpop.gremlin.server.auth.AuthenticatedUser;
+import org.apache.tinkerpop.gremlin.server.authz.AuthorizationException;
+import org.apache.tinkerpop.gremlin.server.authz.Authorizer;
+import org.javatuples.Quartet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Map;
+
+import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST;
+import static io.netty.handler.codec.http.HttpResponseStatus.INTERNAL_SERVER_ERROR;
+import static io.netty.handler.codec.http.HttpResponseStatus.UNAUTHORIZED;
+
+
+/**
+ *  An authorization handler for the http channel that allows the {@link Authorizer} to be plugged into it.
+ *
+ * @author Marc de Lignie
+ */
+@ChannelHandler.Sharable
+public class HttpBasicAuthorizationHandler extends ChannelInboundHandlerAdapter {
+    private static final Logger logger = LoggerFactory.getLogger(HttpBasicAuthorizationHandler.class);
+    private static final Logger auditLogger = LoggerFactory.getLogger(GremlinServer.AUDIT_LOGGER_NAME);
+
+    private AuthenticatedUser user;
+    private final Authorizer authorizer;
+
+    public HttpBasicAuthorizationHandler(Authorizer authorizer) {
+        this.authorizer = authorizer;
+    }
+
+    @Override
+    public void channelRead(final ChannelHandlerContext ctx, final Object msg) {
+        if (msg instanceof FullHttpMessage){
+            final FullHttpMessage request = (FullHttpMessage) msg;
+            final boolean keepAlive = HttpUtil.isKeepAlive(request);
+            try {
+                user = ctx.channel().attr(StateKey.AUTHENTICATED_USER).get();
+                if (null == user) {    // This is expected when using the AllowAllAuthenticator
+                    user = AuthenticatedUser.ANONYMOUS_USER;
+                }
+                final Quartet<String, Map<String, Object>, String, Map<String, String>> requestArguments =
+                        HttpHandlerUtil.getRequestArguments((FullHttpRequest) request);
+                final RequestMessage requestMessage = RequestMessage.build(Tokens.OPS_EVAL).
+                        processor("").
+                        addArg(Tokens.ARGS_GREMLIN, requestArguments.getValue0()).
+                        addArg(Tokens.ARGS_BINDINGS, requestArguments.getValue1()).
+                        addArg(Tokens.ARGS_LANGUAGE, requestArguments.getValue2()).
+                        addArg(Tokens.ARGS_ALIASES, requestArguments.getValue3()).
+                        create();
+                authorizer.authorize(user, requestMessage);
+                ctx.fireChannelRead(request);
+            } catch (AuthorizationException ex) {  // Expected: users can alternate between allowed and disallowed requests
+                String address = ctx.channel().remoteAddress().toString();
+                if (address.startsWith("/") && address.length() > 1) address = address.substring(1);
+                final String script;
+                try {
+                    script = HttpHandlerUtil.getRequestArguments((FullHttpRequest) request).getValue0();
+                } catch (IllegalArgumentException iae) {
+                    HttpHandlerUtil.sendError(ctx, BAD_REQUEST, iae.getMessage(), keepAlive);
+                    return;
+                }
+                auditLogger.info("User {} with address {} attempted an unauthorized http request: {}",
+                    user.getName(), address, script);
+                final String message = String.format("No authorization for script [%s] - check permissions.", script);
+                HttpHandlerUtil.sendError(ctx, UNAUTHORIZED, message, keepAlive);
+                ReferenceCountUtil.release(msg);
+            } catch (Exception ex) {
+                final String message = String.format(
+                        "%s is not ready to handle requests - unknown error", authorizer.getClass().getSimpleName());
+                HttpHandlerUtil.sendError(ctx, INTERNAL_SERVER_ERROR, message, keepAlive);
+                ReferenceCountUtil.release(msg);
+            }
+        } else {
+            logger.warn("{} only processes FullHttpMessage instances - received {} - channel closing",
+                this.getClass().getSimpleName(), msg.getClass());
+            ctx.close();
+        }
+    }
+}
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpGremlinEndpointHandler.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpGremlinEndpointHandler.java
index b2088e4..2ddc202 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpGremlinEndpointHandler.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpGremlinEndpointHandler.java
@@ -18,7 +18,6 @@
  */
 package org.apache.tinkerpop.gremlin.server.handler;
 
-import com.codahale.metrics.Meter;
 import com.codahale.metrics.Timer;
 import org.javatuples.Pair;
 import org.javatuples.Quartet;
@@ -26,7 +25,6 @@
 import org.slf4j.LoggerFactory;
 import org.apache.commons.lang3.exception.ExceptionUtils;
 import org.apache.tinkerpop.gremlin.driver.MessageSerializer;
-import org.apache.tinkerpop.gremlin.driver.Tokens;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
 import org.apache.tinkerpop.gremlin.driver.ser.MessageTextSerializer;
@@ -35,18 +33,13 @@
 import org.apache.tinkerpop.gremlin.server.GraphManager;
 import org.apache.tinkerpop.gremlin.server.GremlinServer;
 import org.apache.tinkerpop.gremlin.server.Settings;
+import org.apache.tinkerpop.gremlin.server.auth.AuthenticatedUser;
 import org.apache.tinkerpop.gremlin.server.util.MetricManager;
 import org.apache.tinkerpop.gremlin.structure.Graph;
 import org.apache.tinkerpop.gremlin.util.function.FunctionUtils;
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
-import org.apache.tinkerpop.shaded.jackson.databind.JsonNode;
-import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
-import org.apache.tinkerpop.shaded.jackson.databind.node.ArrayNode;
-import org.apache.tinkerpop.shaded.jackson.databind.node.ObjectNode;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
-import io.netty.channel.ChannelFuture;
-import io.netty.channel.ChannelFutureListener;
 import io.netty.channel.ChannelHandler;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.ChannelInboundHandlerAdapter;
@@ -57,19 +50,13 @@
 import io.netty.handler.codec.http.FullHttpResponse;
 import io.netty.handler.codec.http.HttpResponseStatus;
 import io.netty.handler.codec.http.HttpUtil;
-import io.netty.handler.codec.http.QueryStringDecoder;
-import io.netty.util.CharsetUtil;
 import io.netty.util.ReferenceCountUtil;
 
 import javax.script.Bindings;
 import javax.script.SimpleBindings;
-import java.io.IOException;
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
@@ -103,24 +90,13 @@
     private static final Logger logger = LoggerFactory.getLogger(HttpGremlinEndpointHandler.class);
     private static final Logger auditLogger = LoggerFactory.getLogger(GremlinServer.AUDIT_LOGGER_NAME);
     private static final Charset UTF8 = StandardCharsets.UTF_8;
-    static final Meter errorMeter = MetricManager.INSTANCE.getMeter(name(GremlinServer.class, "errors"));
-
-    private static final String ARGS_BINDINGS_DOT = Tokens.ARGS_BINDINGS + ".";
-
-    private static final String ARGS_ALIASES_DOT = Tokens.ARGS_ALIASES + ".";
 
     private static final Timer evalOpTimer = MetricManager.INSTANCE.getTimer(name(GremlinServer.class, "op", "eval"));
 
     /**
      * Serializers for the response.
      */
-    private final Map<String, MessageSerializer> serializers;
-
-    /**
-     * This is just a generic mapper to interpret the JSON of a POSTed request.  It is not used for the serialization
-     * of the response.
-     */
-    private static final ObjectMapper mapper = new ObjectMapper();
+    private final Map<String, MessageSerializer<?>> serializers;
 
     private final GremlinExecutor gremlinExecutor;
     private final GraphManager graphManager;
@@ -128,7 +104,7 @@
 
     private static final Pattern pattern = Pattern.compile("(.*);q=(.*)");
 
-    public HttpGremlinEndpointHandler(final Map<String, MessageSerializer> serializers,
+    public HttpGremlinEndpointHandler(final Map<String, MessageSerializer<?>> serializers,
                                       final GremlinExecutor gremlinExecutor,
                                       final GraphManager graphManager,
                                       final Settings settings) {
@@ -145,7 +121,7 @@
             final boolean keepAlive = HttpUtil.isKeepAlive(req);
 
             if ("/favicon.ico".equals(req.uri())) {
-                sendError(ctx, NOT_FOUND, "Gremlin Server doesn't have a favicon.ico", keepAlive);
+                HttpHandlerUtil.sendError(ctx, NOT_FOUND, "Gremlin Server doesn't have a favicon.ico", keepAlive);
                 ReferenceCountUtil.release(msg);
                 return;
             }
@@ -155,24 +131,24 @@
             }
 
             if (req.method() != GET && req.method() != POST) {
-                sendError(ctx, METHOD_NOT_ALLOWED, METHOD_NOT_ALLOWED.toString(), keepAlive);
+                HttpHandlerUtil.sendError(ctx, METHOD_NOT_ALLOWED, METHOD_NOT_ALLOWED.toString(), keepAlive);
                 ReferenceCountUtil.release(msg);
                 return;
             }
 
             final Quartet<String, Map<String, Object>, String, Map<String, String>> requestArguments;
             try {
-                requestArguments = getRequestArguments(req);
+                requestArguments = HttpHandlerUtil.getRequestArguments(req);
             } catch (IllegalArgumentException iae) {
-                sendError(ctx, BAD_REQUEST, iae.getMessage(), keepAlive);
+                HttpHandlerUtil.sendError(ctx, BAD_REQUEST, iae.getMessage(), keepAlive);
                 ReferenceCountUtil.release(msg);
                 return;
             }
 
             final String acceptString = Optional.ofNullable(req.headers().get("Accept")).orElse("application/json");
-            final Pair<String, MessageTextSerializer> serializer = chooseSerializer(acceptString);
+            final Pair<String, MessageTextSerializer<?>> serializer = chooseSerializer(acceptString);
             if (null == serializer) {
-                sendError(ctx, BAD_REQUEST, String.format("no serializer for requested Accept header: %s", acceptString),
+                HttpHandlerUtil.sendError(ctx, BAD_REQUEST, String.format("no serializer for requested Accept header: %s", acceptString),
                         keepAlive);
                 ReferenceCountUtil.release(msg);
                 return;
@@ -186,6 +162,15 @@
             try {
                 logger.debug("Processing request containing script [{}] and bindings of [{}] on {}",
                         requestArguments.getValue0(), requestArguments.getValue1(), Thread.currentThread().getName());
+                if (settings.enableAuditLog) {
+                    AuthenticatedUser user = ctx.channel().attr(StateKey.AUTHENTICATED_USER).get();
+                    if (null == user) {    // This is expected when using the AllowAllAuthenticator
+                        user = AuthenticatedUser.ANONYMOUS_USER;
+                    }
+                    String address = ctx.channel().remoteAddress().toString();
+                    if (address.startsWith("/") && address.length() > 1) address = address.substring(1);
+                    auditLogger.info("User {} with address {} requested: {}", user.getName(), address, requestArguments.getValue0());
+                }
                 if (settings.authentication.enableAuditLog) {
                     String address = ctx.channel().remoteAddress().toString();
                     if (address.startsWith("/") && address.length() > 1) address = address.substring(1);
@@ -205,7 +190,7 @@
                         // handle cors business
                         if (origin != null) response.headers().set(ACCESS_CONTROL_ALLOW_ORIGIN, origin);
 
-                        sendAndCleanupConnection(ctx, keepAlive, response);
+                        HttpHandlerUtil.sendAndCleanupConnection(ctx, keepAlive, response);
                     }
                 });
 
@@ -215,7 +200,7 @@
                 try {
                     bindings = createBindings(requestArguments.getValue1(), requestArguments.getValue3());
                 } catch (IllegalStateException iae) {
-                    sendError(ctx, BAD_REQUEST, iae.getMessage(), keepAlive);
+                    HttpHandlerUtil.sendError(ctx, BAD_REQUEST, iae.getMessage(), keepAlive);
                     ReferenceCountUtil.release(msg);
                     return;
                 }
@@ -251,9 +236,9 @@
 
                 evalFuture.exceptionally(t -> {
                     if (t.getMessage() != null)
-                        sendError(ctx, INTERNAL_SERVER_ERROR, t.getMessage(), Optional.of(t), keepAlive);
+                        HttpHandlerUtil.sendError(ctx, INTERNAL_SERVER_ERROR, t.getMessage(), Optional.of(t), keepAlive);
                     else
-                        sendError(ctx, INTERNAL_SERVER_ERROR, String.format("Error encountered evaluating script: %s", requestArguments.getValue0())
+                        HttpHandlerUtil.sendError(ctx, INTERNAL_SERVER_ERROR, String.format("Error encountered evaluating script: %s", requestArguments.getValue0())
                                 , Optional.of(t), keepAlive);
                     promise.setFailure(t);
                     return null;
@@ -270,11 +255,11 @@
                 // context on whether to close the connection or not, based on keepalive.
                 final Throwable t = ExceptionUtils.getRootCause(ex);
                 if (t instanceof TooLongFrameException) {
-                    sendError(ctx, HttpResponseStatus.REQUEST_ENTITY_TOO_LARGE, t.getMessage() + " - increase the maxContentLength", keepAlive);
+                    HttpHandlerUtil.sendError(ctx, HttpResponseStatus.REQUEST_ENTITY_TOO_LARGE, t.getMessage() + " - increase the maxContentLength", keepAlive);
                 } else if (t != null){
-                    sendError(ctx, INTERNAL_SERVER_ERROR, t.getMessage(), keepAlive);
+                    HttpHandlerUtil.sendError(ctx, INTERNAL_SERVER_ERROR, t.getMessage(), keepAlive);
                 } else {
-                    sendError(ctx, INTERNAL_SERVER_ERROR, ex.getMessage(), keepAlive);
+                    HttpHandlerUtil.sendError(ctx, INTERNAL_SERVER_ERROR, ex.getMessage(), keepAlive);
                 }
             }
         }
@@ -285,7 +270,7 @@
         logger.error("Error processing HTTP Request", cause);
 
         if (ctx.channel().isActive()) {
-            sendError(ctx, INTERNAL_SERVER_ERROR, cause.getMessage(), false);
+            HttpHandlerUtil.sendError(ctx, INTERNAL_SERVER_ERROR, cause.getMessage(), false);
         }
     }
 
@@ -323,7 +308,7 @@
         return bindings;
     }
 
-    private Pair<String, MessageTextSerializer> chooseSerializer(final String acceptString) {
+    private Pair<String, MessageTextSerializer<?>> chooseSerializer(final String acceptString) {
         final List<Pair<String, Double>> ordered = Stream.of(acceptString.split(",")).map(mediaType -> {
             // parse out each mediaType with its params - keeping it simple and just looking for "quality".  if
             // that value isn't there, default it to 1.0.  not really validating here so users better get their
@@ -337,143 +322,12 @@
             // super useful for gremlin server really.
             final String accept = p.getValue0().equals("*/*") ? "application/json" : p.getValue0();
             if (serializers.containsKey(accept))
-                return Pair.with(accept, (MessageTextSerializer) serializers.get(accept));
+                return Pair.with(accept, (MessageTextSerializer<?>) serializers.get(accept));
         }
 
         return null;
     }
 
-    private static Quartet<String, Map<String, Object>, String, Map<String, String>> getRequestArguments(final FullHttpRequest request) {
-        if (request.method() == GET) {
-            final QueryStringDecoder decoder = new QueryStringDecoder(request.uri());
-            final List<String> gremlinParms = decoder.parameters().get(Tokens.ARGS_GREMLIN);
-
-            if (null == gremlinParms || gremlinParms.size() == 0)
-                throw new IllegalArgumentException("no gremlin script supplied");
-            final String script = gremlinParms.get(0);
-            if (script.isEmpty()) throw new IllegalArgumentException("no gremlin script supplied");
-
-            // query string parameters - take the first instance of a key only - ignore the rest
-            final Map<String, Object> bindings = new HashMap<>();
-            decoder.parameters().entrySet().stream().filter(kv -> kv.getKey().startsWith(ARGS_BINDINGS_DOT))
-                    .forEach(kv -> bindings.put(kv.getKey().substring(ARGS_BINDINGS_DOT.length()), kv.getValue().get(0)));
-
-            final Map<String, String> aliases = new HashMap<>();
-            decoder.parameters().entrySet().stream().filter(kv -> kv.getKey().startsWith(ARGS_ALIASES_DOT))
-                    .forEach(kv -> aliases.put(kv.getKey().substring(ARGS_ALIASES_DOT.length()), kv.getValue().get(0)));
-
-            final List<String> languageParms = decoder.parameters().get(Tokens.ARGS_LANGUAGE);
-            final String language = (null == languageParms || languageParms.size() == 0) ? null : languageParms.get(0);
-
-            return Quartet.with(script, bindings, language, aliases);
-        } else {
-            final JsonNode body;
-            try {
-                body = mapper.readTree(request.content().toString(CharsetUtil.UTF_8));
-            } catch (IOException ioe) {
-                throw new IllegalArgumentException("body could not be parsed", ioe);
-            }
-
-            final JsonNode scriptNode = body.get(Tokens.ARGS_GREMLIN);
-            if (null == scriptNode) throw new IllegalArgumentException("no gremlin script supplied");
-
-            final JsonNode bindingsNode = body.get(Tokens.ARGS_BINDINGS);
-            if (bindingsNode != null && !bindingsNode.isObject())
-                throw new IllegalArgumentException("bindings must be a Map");
-
-            final Map<String, Object> bindings = new HashMap<>();
-            if (bindingsNode != null)
-                bindingsNode.fields().forEachRemaining(kv -> bindings.put(kv.getKey(), fromJsonNode(kv.getValue())));
-
-            final JsonNode aliasesNode = body.get(Tokens.ARGS_ALIASES);
-            if (aliasesNode != null && !aliasesNode.isObject())
-                throw new IllegalArgumentException("aliases must be a Map");
-
-            final Map<String, String> aliases = new HashMap<>();
-            if (aliasesNode != null)
-                aliasesNode.fields().forEachRemaining(kv -> aliases.put(kv.getKey(), kv.getValue().asText()));
-
-            final JsonNode languageNode = body.get(Tokens.ARGS_LANGUAGE);
-            final String language = null == languageNode ? null : languageNode.asText();
-
-            return Quartet.with(scriptNode.asText(), bindings, language, aliases);
-        }
-    }
-
-    public static Object fromJsonNode(final JsonNode node) {
-        if (node.isNull())
-            return null;
-        else if (node.isObject()) {
-            final Map<String, Object> map = new HashMap<>();
-            final ObjectNode objectNode = (ObjectNode) node;
-            final Iterator<String> iterator = objectNode.fieldNames();
-            while (iterator.hasNext()) {
-                String key = iterator.next();
-                map.put(key, fromJsonNode(objectNode.get(key)));
-            }
-            return map;
-        } else if (node.isArray()) {
-            final ArrayNode arrayNode = (ArrayNode) node;
-            final ArrayList<Object> array = new ArrayList<>();
-            for (int i = 0; i < arrayNode.size(); i++) {
-                array.add(fromJsonNode(arrayNode.get(i)));
-            }
-            return array;
-        } else if (node.isFloatingPointNumber())
-            return node.asDouble();
-        else if (node.isIntegralNumber())
-            return node.asLong();
-        else if (node.isBoolean())
-            return node.asBoolean();
-        else
-            return node.asText();
-    }
-
-    private static void sendError(final ChannelHandlerContext ctx, final HttpResponseStatus status,
-                                  final String message, final boolean keepAlive) {
-        sendError(ctx, status, message, Optional.empty(), keepAlive);
-    }
-
-    private static void sendError(final ChannelHandlerContext ctx, final HttpResponseStatus status,
-                                  final String message, final Optional<Throwable> t, final boolean keepAlive) {
-        if (t.isPresent())
-            logger.warn(String.format("Invalid request - responding with %s and %s", status, message), t.get());
-        else
-            logger.warn(String.format("Invalid request - responding with %s and %s", status, message));
-
-        errorMeter.mark();
-        final ObjectNode node = mapper.createObjectNode();
-        node.put("message", message);
-        if (t.isPresent()) {
-            // "Exception-Class" needs to go away - didn't realize it was named that way during review for some reason.
-            // replaced with the same method for exception reporting as is used with websocket/nio protocol
-            node.put("Exception-Class", t.get().getClass().getName());
-            final ArrayNode exceptionList = node.putArray(Tokens.STATUS_ATTRIBUTE_EXCEPTIONS);
-            ExceptionUtils.getThrowableList(t.get()).forEach(throwable -> exceptionList.add(throwable.getClass().getName()));
-            node.put(Tokens.STATUS_ATTRIBUTE_STACK_TRACE, ExceptionUtils.getStackTrace(t.get()));
-        }
-
-        final FullHttpResponse response = new DefaultFullHttpResponse(
-                HTTP_1_1, status, Unpooled.copiedBuffer(node.toString(), CharsetUtil.UTF_8));
-        response.headers().set(CONTENT_TYPE, "application/json");
-
-        sendAndCleanupConnection(ctx, keepAlive, response);
-    }
-
-    private static void sendAndCleanupConnection(final ChannelHandlerContext ctx,
-                                                 final boolean keepAlive,
-                                                 final FullHttpResponse response) {
-        HttpUtil.setKeepAlive(response, keepAlive);
-        HttpUtil.setContentLength(response, response.content().readableBytes());
-
-        final ChannelFuture flushPromise = ctx.writeAndFlush(response);
-
-        if (!keepAlive) {
-            // Close the connection as soon as the response is sent.
-            flushPromise.addListener(ChannelFutureListener.CLOSE);
-        }
-    }
-
     private static void attemptCommit(final Map<String, String> aliases, final GraphManager graphManager, final boolean strict) {
         if (strict)
             graphManager.commit(new HashSet<>(aliases.values()));
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpHandlerUtil.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpHandlerUtil.java
new file mode 100644
index 0000000..c1ae1e5
--- /dev/null
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpHandlerUtil.java
@@ -0,0 +1,204 @@
+/*
+ * 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.server.handler;
+
+import com.codahale.metrics.Meter;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelFutureListener;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.http.DefaultFullHttpResponse;
+import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.codec.http.FullHttpResponse;
+import io.netty.handler.codec.http.HttpResponseStatus;
+import io.netty.handler.codec.http.HttpUtil;
+import io.netty.handler.codec.http.QueryStringDecoder;
+import io.netty.util.CharsetUtil;
+import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.apache.tinkerpop.gremlin.driver.Tokens;
+import org.apache.tinkerpop.gremlin.server.GremlinServer;
+import org.apache.tinkerpop.gremlin.server.util.MetricManager;
+import org.apache.tinkerpop.shaded.jackson.databind.JsonNode;
+import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
+import org.apache.tinkerpop.shaded.jackson.databind.node.ArrayNode;
+import org.apache.tinkerpop.shaded.jackson.databind.node.ObjectNode;
+import org.javatuples.Quartet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import static com.codahale.metrics.MetricRegistry.name;
+import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE;
+import static io.netty.handler.codec.http.HttpMethod.GET;
+import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
+
+/**
+ * Provides methods shared by the HTTP handlers.
+ *
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class HttpHandlerUtil {
+    private static final Logger logger = LoggerFactory.getLogger(HttpHandlerUtil.class);
+    static final Meter errorMeter = MetricManager.INSTANCE.getMeter(name(GremlinServer.class, "errors"));
+    private static final String ARGS_BINDINGS_DOT = Tokens.ARGS_BINDINGS + ".";
+    private static final String ARGS_ALIASES_DOT = Tokens.ARGS_ALIASES + ".";
+    /**
+     * This is just a generic mapper to interpret the JSON of a POSTed request.  It is not used for the serialization
+     * of the response.
+     */
+    private static final ObjectMapper mapper = new ObjectMapper();
+
+    static Quartet<String, Map<String, Object>, String, Map<String, String>> getRequestArguments(final FullHttpRequest request) {
+        if (request.method() == GET) {
+            final QueryStringDecoder decoder = new QueryStringDecoder(request.uri());
+            final List<String> gremlinParms = decoder.parameters().get(Tokens.ARGS_GREMLIN);
+
+            if (null == gremlinParms || gremlinParms.size() == 0)
+                throw new IllegalArgumentException("no gremlin script supplied");
+            final String script = gremlinParms.get(0);
+            if (script.isEmpty()) throw new IllegalArgumentException("no gremlin script supplied");
+
+            // query string parameters - take the first instance of a key only - ignore the rest
+            final Map<String, Object> bindings = new HashMap<>();
+            decoder.parameters().entrySet().stream().filter(kv -> kv.getKey().startsWith(ARGS_BINDINGS_DOT))
+                    .forEach(kv -> bindings.put(kv.getKey().substring(ARGS_BINDINGS_DOT.length()), kv.getValue().get(0)));
+
+            final Map<String, String> aliases = new HashMap<>();
+            decoder.parameters().entrySet().stream().filter(kv -> kv.getKey().startsWith(ARGS_ALIASES_DOT))
+                    .forEach(kv -> aliases.put(kv.getKey().substring(ARGS_ALIASES_DOT.length()), kv.getValue().get(0)));
+
+            final List<String> languageParms = decoder.parameters().get(Tokens.ARGS_LANGUAGE);
+            final String language = (null == languageParms || languageParms.size() == 0) ? null : languageParms.get(0);
+
+            return Quartet.with(script, bindings, language, aliases);
+        } else {
+            final JsonNode body;
+            try {
+                body = mapper.readTree(request.content().toString(CharsetUtil.UTF_8));
+            } catch (IOException ioe) {
+                throw new IllegalArgumentException("body could not be parsed", ioe);
+            }
+
+            final JsonNode scriptNode = body.get(Tokens.ARGS_GREMLIN);
+            if (null == scriptNode) throw new IllegalArgumentException("no gremlin script supplied");
+
+            final JsonNode bindingsNode = body.get(Tokens.ARGS_BINDINGS);
+            if (bindingsNode != null && !bindingsNode.isObject())
+                throw new IllegalArgumentException("bindings must be a Map");
+
+            final Map<String, Object> bindings = new HashMap<>();
+            if (bindingsNode != null)
+                bindingsNode.fields().forEachRemaining(kv -> bindings.put(kv.getKey(), fromJsonNode(kv.getValue())));
+
+            final JsonNode aliasesNode = body.get(Tokens.ARGS_ALIASES);
+            if (aliasesNode != null && !aliasesNode.isObject())
+                throw new IllegalArgumentException("aliases must be a Map");
+
+            final Map<String, String> aliases = new HashMap<>();
+            if (aliasesNode != null)
+                aliasesNode.fields().forEachRemaining(kv -> aliases.put(kv.getKey(), kv.getValue().asText()));
+
+            final JsonNode languageNode = body.get(Tokens.ARGS_LANGUAGE);
+            final String language = null == languageNode ? null : languageNode.asText();
+
+            return Quartet.with(scriptNode.asText(), bindings, language, aliases);
+        }
+    }
+
+    private static Object fromJsonNode(final JsonNode node) {
+        if (node.isNull())
+            return null;
+        else if (node.isObject()) {
+            final Map<String, Object> map = new HashMap<>();
+            final ObjectNode objectNode = (ObjectNode) node;
+            final Iterator<String> iterator = objectNode.fieldNames();
+            while (iterator.hasNext()) {
+                String key = iterator.next();
+                map.put(key, fromJsonNode(objectNode.get(key)));
+            }
+            return map;
+        } else if (node.isArray()) {
+            final ArrayNode arrayNode = (ArrayNode) node;
+            final ArrayList<Object> array = new ArrayList<>();
+            for (int i = 0; i < arrayNode.size(); i++) {
+                array.add(fromJsonNode(arrayNode.get(i)));
+            }
+            return array;
+        } else if (node.isFloatingPointNumber())
+            return node.asDouble();
+        else if (node.isIntegralNumber())
+            return node.asLong();
+        else if (node.isBoolean())
+            return node.asBoolean();
+        else
+            return node.asText();
+    }
+
+    static void sendError(final ChannelHandlerContext ctx, final HttpResponseStatus status,
+                          final String message, final boolean keepAlive) {
+        sendError(ctx, status, message, Optional.empty(), keepAlive);
+    }
+
+    static void sendError(final ChannelHandlerContext ctx, final HttpResponseStatus status,
+                          final String message, final Optional<Throwable> t, final boolean keepAlive) {
+        if (t.isPresent())
+            logger.warn(String.format("Invalid request - responding with %s and %s", status, message), t.get());
+        else
+            logger.warn(String.format("Invalid request - responding with %s and %s", status, message));
+
+        errorMeter.mark();
+        final ObjectNode node = mapper.createObjectNode();
+        node.put("message", message);
+        if (t.isPresent()) {
+            // "Exception-Class" needs to go away - didn't realize it was named that way during review for some reason.
+            // replaced with the same method for exception reporting as is used with websocket/nio protocol
+            node.put("Exception-Class", t.get().getClass().getName());
+            final ArrayNode exceptionList = node.putArray(Tokens.STATUS_ATTRIBUTE_EXCEPTIONS);
+            ExceptionUtils.getThrowableList(t.get()).forEach(throwable -> exceptionList.add(throwable.getClass().getName()));
+            node.put(Tokens.STATUS_ATTRIBUTE_STACK_TRACE, ExceptionUtils.getStackTrace(t.get()));
+        }
+
+        final FullHttpResponse response = new DefaultFullHttpResponse(
+                HTTP_1_1, status, Unpooled.copiedBuffer(node.toString(), CharsetUtil.UTF_8));
+        response.headers().set(CONTENT_TYPE, "application/json");
+
+        sendAndCleanupConnection(ctx, keepAlive, response);
+    }
+
+    static void sendAndCleanupConnection(final ChannelHandlerContext ctx,
+                                         final boolean keepAlive,
+                                         final FullHttpResponse response) {
+        HttpUtil.setKeepAlive(response, keepAlive);
+        HttpUtil.setContentLength(response, response.content().readableBytes());
+
+        final ChannelFuture flushPromise = ctx.writeAndFlush(response);
+
+        if (!keepAlive) {
+            // Close the connection as soon as the response is sent.
+            flushPromise.addListener(ChannelFutureListener.CLOSE);
+        }
+    }
+}
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/MultiTaskSession.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/MultiTaskSession.java
new file mode 100644
index 0000000..8765d98
--- /dev/null
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/MultiTaskSession.java
@@ -0,0 +1,296 @@
+/*
+ * 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.server.handler;
+
+import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
+import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
+import org.apache.tinkerpop.gremlin.groovy.engine.GremlinExecutor;
+import org.apache.tinkerpop.gremlin.groovy.jsr223.GroovyCompilerGremlinPlugin;
+import org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngine;
+import org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngineManager;
+import org.apache.tinkerpop.gremlin.server.Settings;
+import org.apache.tinkerpop.gremlin.structure.Transaction;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.script.Bindings;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static org.apache.tinkerpop.gremlin.server.op.session.SessionOpProcessor.CONFIG_GLOBAL_FUNCTION_CACHE_ENABLED;
+
+/**
+ * A {@link Session} implementation that queues tasks given to it and executes them in a serial fashion within the
+ * same thread which thus allows multiple tasks to be executed in the same transaction. The first {@link SessionTask}
+ * to execute is supplied on the constructor and additional ones may be added as they arrive with
+ * {@link #submitTask(SessionTask)} where they will be added to a queue where they will await execution in the thread
+ * bound to this session.
+ */
+public class MultiTaskSession extends AbstractSession {
+    private static final Logger logger = LoggerFactory.getLogger(MultiTaskSession.class);
+    protected final BlockingQueue<SessionTask> queue;
+    private final AtomicBoolean ending = new AtomicBoolean(false);
+    private final ScheduledExecutorService scheduledExecutorService;
+    private final GremlinScriptEngineManager scriptEngineManager;
+    private ScheduledFuture<?> requestCancelFuture;
+    private Bindings bindings;
+
+    /**
+     * Creates a new {@code MultiTaskSession} object providing the initial starting {@link SessionTask} that gets
+     * executed by the session when it starts.
+     *
+     * @param initialSessionTask The tasks that starts the session.
+     * @param sessionId The id of the session
+     * @param sessions The session id to {@link Session} instances mapping
+     */
+    public MultiTaskSession(final SessionTask initialSessionTask, final String sessionId,
+                     final ConcurrentMap<String, Session> sessions) {
+        super(initialSessionTask, sessionId, false, sessions);
+
+        queue = new LinkedBlockingQueue<>(initialSessionTask.getSettings().maxSessionTaskQueueSize);
+
+        // using a global function cache is cheaper than creating a new on per session especially if you have to
+        // create a lot of sessions. it will generate a ton of throw-away objects. mostly keeping the option open
+        // to not use it to preserve the ability to use the old functionality if wanted or if there is some specific
+        // use case with sessions that needs it. if we wanted this could eventually become a per-request option
+        // so that the client could control it as necessary and get scriptengine isolation if they need it.
+        if (initialSessionTask.getSettings().useCommonEngineForSessions)
+            scriptEngineManager = initialSessionTask.getGremlinExecutor().getScriptEngineManager();
+        else
+            scriptEngineManager = initializeGremlinExecutor(initialSessionTask).getScriptEngineManager();
+
+        scheduledExecutorService = initialSessionTask.getScheduledExecutorService();
+
+        // would be odd if this tossed an exception because on construction the queue should be empty,
+        // but let's handle it in the same fashion as if it had been rejected by the queue itself but put up
+        // an additional log because something would be rather off here if we hit this condition
+        if (!submitTask(initialSessionTask)) {
+            logger.error("Task {} rejected on creation of the {} for session {}",
+                    initialSessionTask.getRequestMessage().getRequestId(), this.getClass().getSimpleName(),
+                    getSessionId());
+            final String msg = String.format("Task %s rejected from session %s",
+                    initialSessionTask.getRequestMessage().getRequestId(), getSessionId());
+            throw new RejectedExecutionException(msg);
+        }
+    }
+
+    /**
+     * Gets the script engine specific to this session which is dependent on the
+     * {@link Settings#useCommonEngineForSessions} configuration.
+     */
+    @Override
+    public GremlinScriptEngine getScriptEngine(final SessionTask sessionTask, final String language) {
+        return scriptEngineManager.getEngineByName(language);
+    }
+
+    @Override
+    public boolean isAcceptingTasks() {
+        return !ending.get();
+    }
+
+    @Override
+    public boolean submitTask(final SessionTask sessionTask) throws RejectedExecutionException {
+        try {
+            return isAcceptingTasks() && queue.add(sessionTask);
+        } catch (IllegalStateException ise) {
+            final String msg = String.format("Task %s rejected from session %s",
+                    sessionTask.getRequestMessage().getRequestId(), getSessionId());
+            throw new RejectedExecutionException(msg);
+        }
+    }
+
+    @Override
+    public void run() {
+        // allow the Session to know about the thread that is running it which will be a thread from the gremlinPool
+        // the thread really only has relevance once the session has started. this thread is then held below in the
+        // while() loop awaiting items to arrive on the request queue. it will hold until the session is properly
+        // closed by the client or through interruption/error
+        this.sessionThread = Thread.currentThread();
+
+        // there must be one item in the queue at least since addTask() gets called before the worker
+        // is ever started
+        SessionTask sessionTask = queue.poll();
+        if (null == sessionTask)
+            throw new IllegalStateException(String.format("Worker has no initial context for session: %s", getSessionId()));
+
+        try {
+            startTransaction(sessionTask);
+            try {
+                while (true) {
+                    // schedule timeout for the current request from the queue
+                    final long seto = sessionTask.getRequestTimeout();
+                    requestCancelFuture = scheduledExecutorService.schedule(
+                            () -> this.triggerTimeout(seto, false),
+                            seto, TimeUnit.MILLISECONDS);
+
+                    // only stop processing stuff in the queue if this session isn't configured to hold state between
+                    // exceptions (i.e. the old OpProcessor way) or if this session is closing down by certain death
+                    // (i.e. channel close or lifetime session timeout)
+                    try {
+                        process(sessionTask);
+                    } catch (SessionException ex) {
+                        if (!maintainStateAfterException || closeReason.get() == CloseReason.CHANNEL_CLOSED ||
+                            closeReason.get() == CloseReason.SESSION_TIMEOUT) {
+                            throw ex;
+                        }
+
+                        // reset the close reason as we are maintaining state
+                        closeReason.set(null);
+
+                        logger.warn(ex.getMessage(), ex);
+                        sessionTask.writeAndFlush(ex.getResponseMessage());
+                    }
+
+                    // work is done within the timeout period so cancel it
+                    cancelRequestTimeout();
+
+                    sessionTask = queue.take();
+                }
+            } catch (Exception ex) {
+                stopAcceptingRequests();
+
+                // the current context gets its exception handled...
+                handleException(sessionTask, ex);
+            }
+        } catch (SessionException rexex) {
+            // if the close reason isn't already set then things stopped during gremlin execution somewhere and not
+            // more external issues like channel close or timeouts.
+            closeReason.compareAndSet(null, CloseReason.PROCESSING_EXCEPTION);
+
+            // remaining work items in the queue are ignored since this worker is closing. must send
+            // back some sort of response to satisfy the client. writeAndFlush code is different than
+            // the ResponseMessage as we don't want the message to be "final" for the Context. that
+            // status must be reserved for the message that caused the error
+            for (SessionTask st : queue) {
+                st.writeAndFlush(ResponseStatusCode.PARTIAL_CONTENT, ResponseMessage.build(st.getRequestMessage())
+                        .code(ResponseStatusCode.SERVER_ERROR)
+                        .statusMessage(String.format(
+                                "An earlier request [%s] failed prior to this one having a chance to execute",
+                                sessionTask.getRequestMessage().getRequestId())).create());
+            }
+
+            // exception should trigger a rollback in the session. a more focused rollback may have occurred
+            // during process() and the related result iteration IF transaction management was enabled on
+            // the request
+            closeTransactionSafely(Transaction.Status.ROLLBACK);
+
+            // the current context could already be completed with SUCCESS and we're just waiting for another
+            // one to show up while a timeout occurs or the channel closes. in these cases, this would be a valid
+            // close in all likelihood so there's no reason to log or alert the client as the client already has
+            // the best answer
+            if (!sessionTask.isFinalResponseWritten()) {
+                logger.warn(rexex.getMessage(), rexex);
+                sessionTask.writeAndFlush(rexex.getResponseMessage());
+            }
+        } finally {
+            // if this is a normal end to the session or if there is some general processing exception which tanks
+            // the entire session or if the session life timeout is exceeded then the  session needs to be removed
+            // and everything cleaned up
+            if (closeReason.compareAndSet(null, CloseReason.EXIT_PROCESSING) ||
+                    closeReason.get() == CloseReason.PROCESSING_EXCEPTION ||
+                    closeReason.get() == CloseReason.SESSION_TIMEOUT) {
+                close();
+            }
+        }
+    }
+
+    /**
+     * This method stops incoming requests from being added to the session queue. It then cancels the session lifetime
+     * timeout and then calls {@link super#close()} which will then interrupt this {@link #run()} which will clear out
+     * remaining requests in the queue. This latter part of the close, where the interruption is concerned, is an
+     * asynchronous operation and will not block as it finishes its processing in the "gremlinPool" thread that was
+     * originally handling the work.
+     */
+    @Override
+    public void close() {
+        stopAcceptingRequests();
+        cancelRequestTimeout();
+        super.close();
+        logger.debug("Session {} closed", getSessionId());
+    }
+
+    private void cancelRequestTimeout() {
+        if (requestCancelFuture != null && !requestCancelFuture.isDone())
+            requestCancelFuture.cancel(true);
+        else
+            logger.debug("Could not cancel request timeout for {} - {}", getSessionId(), requestCancelFuture);
+    }
+
+    private void stopAcceptingRequests() {
+        if (ending.compareAndSet(false, true))
+            cancel(true);
+    }
+
+    @Override
+    protected Bindings getWorkerBindings() throws SessionException {
+        if (null == bindings)
+            bindings = super.getWorkerBindings();
+        return this.bindings;
+    }
+
+    protected GremlinExecutor initializeGremlinExecutor(final SessionTask sessionTask) {
+        final Settings settings = sessionTask.getSettings();
+        final ExecutorService executor = sessionTask.getGremlinExecutor().getExecutorService();
+        final boolean useGlobalFunctionCache = settings.useGlobalFunctionCacheForSessions;
+
+        // these initial settings don't matter so much as we don't really execute things through the
+        // GremlinExecutor directly. Just doing all this setup to make GremlinExecutor do the work of
+        // rigging up the GremlinScriptEngineManager.
+        final GremlinExecutor.Builder gremlinExecutorBuilder = GremlinExecutor.build()
+                .evaluationTimeout(settings.getEvaluationTimeout())
+                .executorService(executor)
+                .globalBindings(graphManager.getAsBindings())
+                .scheduledExecutorService(scheduledExecutorService);
+
+        settings.scriptEngines.forEach((k, v) -> {
+            // use plugins if they are present
+            if (!v.plugins.isEmpty()) {
+                // make sure that server related classes are available at init. the LifeCycleHook stuff will be
+                // added explicitly via configuration using GremlinServerGremlinModule in the yaml. need to override
+                // scriptengine settings with SessionOpProcessor specific ones as the processing for sessions is
+                // different and a global setting may not make sense for a session
+                if (v.plugins.containsKey(GroovyCompilerGremlinPlugin.class.getName())) {
+                    v.plugins.get(GroovyCompilerGremlinPlugin.class.getName()).put(CONFIG_GLOBAL_FUNCTION_CACHE_ENABLED, useGlobalFunctionCache);
+                } else {
+                    final Map<String,Object> pluginConf = new HashMap<>();
+                    pluginConf.put(CONFIG_GLOBAL_FUNCTION_CACHE_ENABLED, useGlobalFunctionCache);
+                    v.plugins.put(GroovyCompilerGremlinPlugin.class.getName(), pluginConf);
+                }
+
+                gremlinExecutorBuilder.addPlugins(k, v.plugins);
+            }
+        });
+
+        return gremlinExecutorBuilder.create();
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s - session: %s", MultiTaskSession.class.getSimpleName(), getSessionId());
+    }
+}
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/NioGremlinBinaryRequestDecoder.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/NioGremlinBinaryRequestDecoder.java
deleted file mode 100644
index 5709143..0000000
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/NioGremlinBinaryRequestDecoder.java
+++ /dev/null
@@ -1,102 +0,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.
- */
-package org.apache.tinkerpop.gremlin.server.handler;
-
-import io.netty.handler.codec.ReplayingDecoder;
-import io.netty.util.CharsetUtil;
-import org.apache.tinkerpop.gremlin.driver.MessageSerializer;
-import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
-import org.apache.tinkerpop.gremlin.driver.ser.SerializationException;
-import io.netty.buffer.ByteBuf;
-import io.netty.channel.ChannelHandlerContext;
-import org.apache.tinkerpop.gremlin.driver.simple.WebSocketClient;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * @author Stephen Mallette (http://stephen.genoprime.com)
- *
- * @deprecated As of release 3.3.10, not replaced, use {@link WebSocketClient}.
- */
-@Deprecated
-public class NioGremlinBinaryRequestDecoder extends ReplayingDecoder<NioGremlinBinaryRequestDecoder.DecoderState> {
-    private static final Logger logger = LoggerFactory.getLogger(NioGremlinBinaryRequestDecoder.class);
-    private final Map<String, MessageSerializer> serializers;
-    private int messageLength;
-
-    public NioGremlinBinaryRequestDecoder(final Map<String, MessageSerializer> serializers) {
-        super(DecoderState.MESSAGE_LENGTH);
-        this.serializers = serializers;
-    }
-
-    @Override
-    protected void decode(final ChannelHandlerContext channelHandlerContext, final ByteBuf byteBuf, final List<Object> objects) throws Exception {
-        switch (state()) {
-            case MESSAGE_LENGTH:
-                messageLength = byteBuf.readInt();
-                checkpoint(DecoderState.MESSAGE);
-            case MESSAGE:
-                try {
-                    final ByteBuf messageFrame = byteBuf.readBytes(messageLength);
-                    final int contentTypeLength = messageFrame.readByte();
-                    final ByteBuf contentTypeFrame = messageFrame.readBytes(contentTypeLength);
-                    final String contentType = contentTypeFrame.toString(CharsetUtil.UTF_8);
-
-                    // the default serializer to use has been GraphSON 1.0 to this point (which was probably bad),
-                    // so maintain that for 3.3.x
-                    final MessageSerializer serializer = select(contentType, ServerSerializers.DEFAULT_SERIALIZER);
-
-                    // it's important to re-initialize these channel attributes as they apply globally to the channel. in
-                    // other words, the next request to this channel might not come with the same configuration and mixed
-                    // state can carry through from one request to the next
-                    channelHandlerContext.channel().attr(StateKey.SESSION).set(null);
-                    channelHandlerContext.channel().attr(StateKey.SERIALIZER).set(serializer);
-                    channelHandlerContext.channel().attr(StateKey.USE_BINARY).set(true);
-
-                    // subtract the contentTypeLength and the byte that held it from the full message length to
-                    // figure out how long the rest of the message is
-                    final int payloadLength = messageLength - 1 - contentTypeLength;
-                    objects.add(serializer.deserializeRequest(messageFrame.readBytes(payloadLength)));
-                } catch (SerializationException se) {
-                    objects.add(RequestMessage.INVALID);
-                }
-
-                checkpoint(DecoderState.MESSAGE_LENGTH);
-                break;
-            default:
-                throw new Error("Invalid message sent to Gremlin Server");
-        }
-    }
-
-    public MessageSerializer select(final String mimeType, final MessageSerializer defaultSerializer) {
-        if (logger.isWarnEnabled() && !serializers.containsKey(mimeType))
-            logger.warn("Gremlin Server is not configured with a serializer for the requested mime type [{}] - using {} by default",
-                    mimeType, defaultSerializer.getClass().getName());
-
-        return serializers.getOrDefault(mimeType, defaultSerializer);
-    }
-
-    public enum DecoderState {
-        MESSAGE_LENGTH,
-        MESSAGE
-    }
-}
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/NioGremlinResponseFrameEncoder.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/NioGremlinResponseFrameEncoder.java
deleted file mode 100644
index 7bfc98e..0000000
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/NioGremlinResponseFrameEncoder.java
+++ /dev/null
@@ -1,50 +0,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.
- */
-package org.apache.tinkerpop.gremlin.server.handler;
-
-import io.netty.buffer.ByteBuf;
-import io.netty.channel.ChannelHandler;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.handler.codec.MessageToByteEncoder;
-import io.netty.util.CharsetUtil;
-import org.apache.tinkerpop.gremlin.driver.simple.WebSocketClient;
-
-/**
- * Encodes {@code ByteBuf} and {@code String} values to bytes to be written over NIO.
- *
- * @author Stephen Mallette (http://stephen.genoprime.com)
- * @deprecated As of release 3.3.10, not replaced, use {@link WebSocketClient}.
- */
-@Deprecated
-@ChannelHandler.Sharable
-public class NioGremlinResponseFrameEncoder extends MessageToByteEncoder<Frame> {
-    @Override
-    protected void encode(final ChannelHandlerContext ctx, final Frame frame, final ByteBuf byteBuf) throws Exception {
-        if (frame.getMsg() instanceof ByteBuf) {
-            final ByteBuf bytes = (ByteBuf) frame.getMsg();
-            byteBuf.writeInt(bytes.capacity());
-            byteBuf.writeBytes(bytes);
-            bytes.release();
-        } else if (frame.getMsg() instanceof String) {
-            final byte [] bytes = ((String) frame.getMsg()).getBytes(CharsetUtil.UTF_8);
-            byteBuf.writeInt(bytes.length);
-            byteBuf.writeBytes(bytes);
-        }
-    }
-}
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/SaslAndHttpBasicAuthenticationHandler.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/SaslAndHttpBasicAuthenticationHandler.java
index 078dfc1..31dabd0 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/SaslAndHttpBasicAuthenticationHandler.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/SaslAndHttpBasicAuthenticationHandler.java
@@ -21,14 +21,14 @@
 
 import io.netty.channel.ChannelHandler;
 import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
 import io.netty.channel.ChannelPipeline;
 import io.netty.handler.codec.http.HttpMessage;
 import org.apache.tinkerpop.gremlin.server.auth.Authenticator;
 import org.apache.tinkerpop.gremlin.server.Settings;
-import org.apache.tinkerpop.gremlin.server.handler.HttpBasicAuthenticationHandler;
-import org.apache.tinkerpop.gremlin.server.handler.SaslAuthenticationHandler;
-import org.apache.tinkerpop.gremlin.server.handler.WebSocketHandlerUtil;
+import org.apache.tinkerpop.gremlin.server.authz.Authorizer;
 
+import static org.apache.tinkerpop.gremlin.server.AbstractChannelizer.PIPELINE_AUTHORIZER;
 import static org.apache.tinkerpop.gremlin.server.channel.WebSocketChannelizer.PIPELINE_AUTHENTICATOR;
 
 /**
@@ -39,19 +39,33 @@
 
     private final String HTTP_AUTH = "http-authentication";
 
-    public SaslAndHttpBasicAuthenticationHandler(final Authenticator authenticator, 
-                                                 final Settings.AuthenticationSettings authenticationSettings) {
-        super(authenticator, authenticationSettings);
+    /**
+     * @deprecated As of release 3.5.0, replaced by {@link #SaslAndHttpBasicAuthenticationHandler(Authenticator, Authorizer, Settings)}.
+     */
+    @Deprecated
+    public SaslAndHttpBasicAuthenticationHandler(final Authenticator authenticator, final Settings settings) {
+        this(authenticator, null, settings);
+    }
+
+    public SaslAndHttpBasicAuthenticationHandler(final Authenticator authenticator, final Authorizer authorizer, final Settings settings) {
+        super(authenticator, authorizer, settings);
     }
 
     @Override
     public void channelRead(final ChannelHandlerContext ctx, final Object obj) throws Exception {
         if (obj instanceof HttpMessage && !WebSocketHandlerUtil.isWebSocket((HttpMessage)obj)) {
-            ChannelPipeline pipeline = ctx.pipeline();
+            final ChannelPipeline pipeline = ctx.pipeline();
             if (null != pipeline.get(HTTP_AUTH)) {
                 pipeline.remove(HTTP_AUTH);
             }
-            pipeline.addAfter(PIPELINE_AUTHENTICATOR, HTTP_AUTH, new HttpBasicAuthenticationHandler(authenticator, this.authenticationSettings));
+            pipeline.addAfter(PIPELINE_AUTHENTICATOR, HTTP_AUTH, new HttpBasicAuthenticationHandler(authenticator, this.settings));
+
+            if (authorizer != null) {
+                final ChannelInboundHandlerAdapter authorizationHandler = new HttpBasicAuthorizationHandler(authorizer);
+                pipeline.remove(PIPELINE_AUTHORIZER);
+                pipeline.addAfter(HTTP_AUTH, PIPELINE_AUTHORIZER, authorizationHandler);
+            }
+
             ctx.fireChannelRead(obj);
         } else {
             super.channelRead(ctx, obj);
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/SaslAuthenticationHandler.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/SaslAuthenticationHandler.java
index 66defec..2adc97f 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/SaslAuthenticationHandler.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/SaslAuthenticationHandler.java
@@ -21,8 +21,6 @@
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelHandler;
 import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.ChannelInboundHandlerAdapter;
-import io.netty.handler.codec.base64.Base64Decoder;
 import io.netty.util.Attribute;
 
 import java.net.InetAddress;
@@ -37,13 +35,12 @@
 import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
-import org.apache.tinkerpop.gremlin.server.Context;
 import org.apache.tinkerpop.gremlin.server.GremlinServer;
 import org.apache.tinkerpop.gremlin.server.Settings;
 import org.apache.tinkerpop.gremlin.server.auth.AuthenticatedUser;
 import org.apache.tinkerpop.gremlin.server.auth.AuthenticationException;
 import org.apache.tinkerpop.gremlin.server.auth.Authenticator;
-import org.apache.tinkerpop.gremlin.server.channel.NioChannelizer;
+import org.apache.tinkerpop.gremlin.server.authz.Authorizer;
 import org.apache.tinkerpop.gremlin.server.channel.WebSocketChannelizer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -51,7 +48,6 @@
 /**
  * A SASL authentication handler that allows the {@link Authenticator} to be plugged into it. This handler is meant
  * to be used with protocols that process a {@link RequestMessage} such as the {@link WebSocketChannelizer}
- * or the {@link NioChannelizer}
  *
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
@@ -62,11 +58,19 @@
     private static final Base64.Encoder BASE64_ENCODER = Base64.getEncoder();
     private static final Logger auditLogger = LoggerFactory.getLogger(GremlinServer.AUDIT_LOGGER_NAME);
 
-    protected final Settings.AuthenticationSettings authenticationSettings;
+    protected final Settings settings;
 
-    public SaslAuthenticationHandler(final Authenticator authenticator, final Settings.AuthenticationSettings authenticationSettings) {
-        super(authenticator);
-        this.authenticationSettings = authenticationSettings;
+    /**
+     * @deprecated As of release 3.5.0, replaced by {@link #SaslAuthenticationHandler(Authenticator, Authorizer, Settings)}.
+     */
+    @Deprecated
+    public SaslAuthenticationHandler(final Authenticator authenticator, final Settings settings) {
+        this(authenticator, null, settings);
+    }
+
+    public SaslAuthenticationHandler(final Authenticator authenticator, final Authorizer authorizer, final Settings settings) {
+        super(authenticator, authorizer);
+        this.settings = settings;
     }
 
     @Override
@@ -116,8 +120,9 @@
                         final byte[] saslMessage = negotiator.get().evaluateResponse(saslResponse);
                         if (negotiator.get().isComplete()) {
                             final AuthenticatedUser user = negotiator.get().getAuthenticatedUser();
+                            ctx.channel().attr(StateKey.AUTHENTICATED_USER).set(user);
                             // User name logged with the remote socket address and authenticator classname for audit logging
-                            if (authenticationSettings.enableAuditLog) {
+                            if (settings.enableAuditLog || settings.authentication.enableAuditLog) {
                                 String address = ctx.channel().remoteAddress().toString();
                                 if (address.startsWith("/") && address.length() > 1) address = address.substring(1);
                                 final String[] authClassParts = authenticator.getClass().toString().split("[.]");
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/ServerSerializers.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/ServerSerializers.java
index 3981867..32c13da 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/ServerSerializers.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/ServerSerializers.java
@@ -19,7 +19,10 @@
 package org.apache.tinkerpop.gremlin.server.handler;
 
 import org.apache.tinkerpop.gremlin.driver.MessageSerializer;
-import org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV1d0;
+import org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1;
+import org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV3d0;
+import org.apache.tinkerpop.gremlin.structure.io.binary.GraphBinaryMapper;
+import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
 
 /**
  * @author Stephen Mallette (http://stephen.genoprime.com)
@@ -29,9 +32,15 @@
     private ServerSerializers() {}
 
     /**
-     * Default serializer used by the server when the serializer requested does not match what is on the server.
-     * Using GraphSON 1.0 on 3.3.5 because that's what it has long been set to in previous versions.
+     * Default binary serializer used by the server when the serializer requested does not match what is on the server.
+     * This defaults to GraphBinary 1.0.
      */
-    static final MessageSerializer DEFAULT_SERIALIZER = new GraphSONMessageSerializerV1d0();
+    static final MessageSerializer<GraphBinaryMapper> DEFAULT_BINARY_SERIALIZER = new GraphBinaryMessageSerializerV1();
+
+    /**
+     * Default binary serializer used by the server when the serializer requested does not match what is on the server.
+     * This defaults to GraphSON 3.0.
+     */
+    static final MessageSerializer<ObjectMapper> DEFAULT_TEXT_SERIALIZER = new GraphSONMessageSerializerV3d0();
 
 }
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/Session.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/Session.java
new file mode 100644
index 0000000..3849b84
--- /dev/null
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/Session.java
@@ -0,0 +1,84 @@
+/*
+ * 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.server.handler;
+
+import com.codahale.metrics.Timer;
+import io.netty.channel.Channel;
+import org.apache.tinkerpop.gremlin.server.GremlinServer;
+import org.apache.tinkerpop.gremlin.server.util.MetricManager;
+
+import java.util.concurrent.Future;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ScheduledFuture;
+
+import static com.codahale.metrics.MetricRegistry.name;
+
+/**
+ * Requests that arrive through the {@link UnifiedHandler} are all processed within a {@code Session} implementation.
+ * A session accepts a {@link SessionTask} as the work it is meant to perform and those tasks are constructed from
+ * incoming requests. A session may be as short-lived as processing a single task before exiting, as with the
+ * {@link SingleTaskSession} or may be longer-lived by handling multiple tasks, as with the {@link MultiTaskSession}.
+ */
+public interface Session extends Runnable {
+
+    public static final Timer traversalOpTimer = MetricManager.INSTANCE.getTimer(name(GremlinServer.class, "op", "traversal"));
+    public static final Timer evalOpTimer = MetricManager.INSTANCE.getTimer(name(GremlinServer.class, "op", "eval"));
+
+    /**
+     * Gets the identifier for the session.
+     */
+    String getSessionId();
+
+    /**
+     * Adds a task for session to complete.
+     *
+     * @throws RejectedExecutionException if the task cannot be queued
+     */
+    boolean submitTask(final SessionTask sessionTask) throws RejectedExecutionException;
+
+    /**
+     * Sets a reference to the job that will cancel this session if it exceeds its timeout period.
+     */
+    void setSessionCancelFuture(final ScheduledFuture<?> f);
+
+    /**
+     * Sets a reference to the job itself that is running this session.
+     */
+    void setSessionFuture(final Future<?> f);
+
+    /**
+     * Provides a general way to interrupt the session by way of a timeout.
+     *
+     * @param timeout the length of time that passed for the timeout to have triggered
+     * @param causedBySession determines if the timeout triggered due to a particular request (i.e. {@code false} or
+     *                        because of the session lifetime (i.e. {@code true}
+     */
+    void triggerTimeout(final long timeout, boolean causedBySession);
+
+    /**
+     * Determines if the supplied {@code Channel} object is the same as the one bound to the {@code Session}.
+     */
+    boolean isBoundTo(final Channel channel);
+
+    /**
+     * Determines if this session can accept additional tasks or not.
+     */
+    boolean isAcceptingTasks();
+
+}
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/SessionException.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/SessionException.java
new file mode 100644
index 0000000..cf577e2
--- /dev/null
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/SessionException.java
@@ -0,0 +1,43 @@
+/*
+ * 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.server.handler;
+
+import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
+
+/**
+ * An exception that holds the error-related {@link ResponseMessage} which is meant to be returned to the calling
+ * client.
+ */
+public class SessionException extends Exception {
+    private final ResponseMessage responseMessage;
+
+    public SessionException(final String message, final ResponseMessage responseMessage) {
+        super(message);
+        this.responseMessage = responseMessage;
+    }
+
+    public SessionException(final String message, final Throwable cause, final ResponseMessage responseMessage) {
+        super(message, cause);
+        this.responseMessage = responseMessage;
+    }
+
+    public ResponseMessage getResponseMessage() {
+        return this.responseMessage;
+    }
+}
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/SessionTask.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/SessionTask.java
new file mode 100644
index 0000000..57c84f7
--- /dev/null
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/SessionTask.java
@@ -0,0 +1,42 @@
+/*
+ * 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.server.handler;
+
+import io.netty.channel.ChannelHandlerContext;
+import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
+import org.apache.tinkerpop.gremlin.groovy.engine.GremlinExecutor;
+import org.apache.tinkerpop.gremlin.server.Context;
+import org.apache.tinkerpop.gremlin.server.GraphManager;
+import org.apache.tinkerpop.gremlin.server.OpProcessor;
+import org.apache.tinkerpop.gremlin.server.Settings;
+
+import java.util.concurrent.ScheduledExecutorService;
+
+/**
+ * A {@code SessionTask} equates to a particular incoming request to the {@link UnifiedHandler} and is analogous to
+ * a {@link Context} in the {@link OpProcessor} approach to handling requests to the server.
+ */
+public class SessionTask extends Context {
+    public SessionTask(final RequestMessage requestMessage, final ChannelHandlerContext ctx,
+                       final Settings settings, final GraphManager graphManager,
+                       final GremlinExecutor gremlinExecutor,
+                       final ScheduledExecutorService scheduledExecutorService) {
+        super(requestMessage, ctx, settings, graphManager, gremlinExecutor, scheduledExecutorService);
+    }
+}
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/SingleTaskSession.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/SingleTaskSession.java
new file mode 100644
index 0000000..32f1fbc
--- /dev/null
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/SingleTaskSession.java
@@ -0,0 +1,92 @@
+/*
+ * 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.server.handler;
+
+import org.apache.tinkerpop.gremlin.structure.Transaction;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.RejectedExecutionException;
+
+/**
+ * A simple {@link Session} implementation that accepts one request, processes it and exits.
+ */
+public class SingleTaskSession extends AbstractSession {
+    private static final Logger logger = LoggerFactory.getLogger(SingleTaskSession.class);
+    protected final SessionTask onlySessionTask;
+
+    /**
+     * Constructs a {@code SingleTaskSession} that has the task to execute supplied on construction.
+     */
+    public SingleTaskSession(final SessionTask onlySessionTask, final String sessionId,
+                             final ConcurrentMap<String, Session> sessions) {
+        super(onlySessionTask, sessionId,true, sessions);
+        this.onlySessionTask = onlySessionTask;
+    }
+
+    /**
+     * The {@code SingleWorker} can only process one request so the initial construction of it already has the
+     * request in it and no more can be added, therefore this method always return {@code false}.
+     */
+    @Override
+    public boolean isAcceptingTasks() {
+        return false;
+    }
+
+    /**
+     * This implementation only take a single {@link SessionTask} on construction - no additional tasks can be
+     * submitted.
+     */
+    @Override
+    public boolean submitTask(final SessionTask sessionTask) throws RejectedExecutionException {
+        throw new UnsupportedOperationException("SingleWorker doesn't accept tasks beyond the one provided to the constructor");
+    }
+
+    @Override
+    public void run() {
+        // allow the Session to know about the thread that is running it - the thread really only has relevance
+        // once the session has started.
+        this.sessionThread = Thread.currentThread();
+
+        try {
+            startTransaction(onlySessionTask);
+            process(onlySessionTask);
+        } catch (SessionException we) {
+            // if the close reason isn't already set then things stopped during gremlin execution somewhere and not
+            // more external issues like channel close or timeouts.
+            closeReason.compareAndSet(null, CloseReason.PROCESSING_EXCEPTION);
+
+            logger.warn(we.getMessage(), we);
+
+            // should have already rolledback - this is a safety valve
+            closeTransactionSafely(onlySessionTask, Transaction.Status.ROLLBACK);
+
+            onlySessionTask.writeAndFlush(we.getResponseMessage());
+        } finally {
+            closeReason.compareAndSet(null, CloseReason.EXIT_PROCESSING);
+            close();
+        }
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s - session: %s", SingleTaskSession.class.getSimpleName(), getSessionId());
+    }
+}
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/StateKey.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/StateKey.java
index 3d7c8c7..4b5f581 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/StateKey.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/StateKey.java
@@ -20,6 +20,7 @@
 
 import org.apache.tinkerpop.gremlin.driver.MessageSerializer;
 import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
+import org.apache.tinkerpop.gremlin.server.auth.AuthenticatedUser;
 import org.apache.tinkerpop.gremlin.server.auth.Authenticator;
 import org.apache.tinkerpop.gremlin.server.op.session.Session;
 import io.netty.util.AttributeKey;
@@ -36,7 +37,7 @@
     /**
      * The key for the current serializer requested by the client.
      */
-    public static final AttributeKey<MessageSerializer> SERIALIZER = AttributeKey.valueOf("serializer");
+    public static final AttributeKey<MessageSerializer<?>> SERIALIZER = AttributeKey.valueOf("serializer");
 
     /**
      * The key to indicate if the serializer should use its binary format.
@@ -57,4 +58,9 @@
      * The key for the current request.
      */
     public static final AttributeKey<RequestMessage> REQUEST_MESSAGE = AttributeKey.valueOf("request");
+
+    /**
+     * The key for the current {@link AuthenticatedUser}.
+     */
+    public static final AttributeKey<AuthenticatedUser> AUTHENTICATED_USER = AttributeKey.valueOf("authenticatedUser");
 }
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/UnifiedHandler.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/UnifiedHandler.java
new file mode 100644
index 0000000..61ea743
--- /dev/null
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/UnifiedHandler.java
@@ -0,0 +1,345 @@
+/*
+ * 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.server.handler;
+
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.handler.timeout.IdleState;
+import io.netty.handler.timeout.IdleStateEvent;
+import io.netty.util.ReferenceCountUtil;
+import org.apache.tinkerpop.gremlin.driver.Tokens;
+import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
+import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
+import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
+import org.apache.tinkerpop.gremlin.groovy.engine.GremlinExecutor;
+import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
+import org.apache.tinkerpop.gremlin.process.traversal.Operator;
+import org.apache.tinkerpop.gremlin.process.traversal.Order;
+import org.apache.tinkerpop.gremlin.process.traversal.Pop;
+import org.apache.tinkerpop.gremlin.process.traversal.Scope;
+import org.apache.tinkerpop.gremlin.server.Channelizer;
+import org.apache.tinkerpop.gremlin.server.GraphManager;
+import org.apache.tinkerpop.gremlin.server.Settings;
+import org.apache.tinkerpop.gremlin.server.channel.UnifiedChannelizer;
+import org.apache.tinkerpop.gremlin.structure.Column;
+import org.apache.tinkerpop.gremlin.structure.T;
+import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Handler for websockets to be used with the {@link UnifiedChannelizer}.
+ */
+@ChannelHandler.Sharable
+public class UnifiedHandler extends SimpleChannelInboundHandler<RequestMessage> {
+    private static final Logger logger = LoggerFactory.getLogger(UnifiedHandler.class);
+
+    protected final Settings settings;
+    protected final GraphManager graphManager;
+    protected final GremlinExecutor gremlinExecutor;
+    protected final ScheduledExecutorService scheduledExecutorService;
+    protected final ExecutorService sessionExecutor;
+    protected final Channelizer channelizer;
+
+    protected final ConcurrentMap<String, Session> sessions = new ConcurrentHashMap<>();
+
+    /**
+     * This may or may not be the full set of invalid binding keys.  It is dependent on the static imports made to
+     * Gremlin Server.  This should get rid of the worst offenders though and provide a good message back to the
+     * calling client.
+     * <p/>
+     * Use of {@code toUpperCase()} on the accessor values of {@link T} solves an issue where the {@code ScriptEngine}
+     * ignores private scope on {@link T} and imports static fields.
+     */
+    protected static final Set<String> INVALID_BINDINGS_KEYS = new HashSet<>();
+
+    static {
+        INVALID_BINDINGS_KEYS.addAll(Arrays.asList(
+                T.id.name(), T.key.name(),
+                T.label.name(), T.value.name(),
+                T.id.getAccessor(), T.key.getAccessor(),
+                T.label.getAccessor(), T.value.getAccessor(),
+                T.id.getAccessor().toUpperCase(), T.key.getAccessor().toUpperCase(),
+                T.label.getAccessor().toUpperCase(), T.value.getAccessor().toUpperCase()));
+
+        for (Column enumItem : Column.values()) {
+            INVALID_BINDINGS_KEYS.add(enumItem.name());
+        }
+
+        for (Order enumItem : Order.values()) {
+            INVALID_BINDINGS_KEYS.add(enumItem.name());
+        }
+
+        for (Operator enumItem : Operator.values()) {
+            INVALID_BINDINGS_KEYS.add(enumItem.name());
+        }
+
+        for (Scope enumItem : Scope.values()) {
+            INVALID_BINDINGS_KEYS.add(enumItem.name());
+        }
+
+        for (Pop enumItem : Pop.values()) {
+            INVALID_BINDINGS_KEYS.add(enumItem.name());
+        }
+    }
+
+    public UnifiedHandler(final Settings settings, final GraphManager graphManager,
+                          final GremlinExecutor gremlinExecutor,
+                          final ScheduledExecutorService scheduledExecutorService,
+                          final Channelizer channelizer) {
+        this.settings = settings;
+        this.graphManager = graphManager;
+        this.gremlinExecutor = gremlinExecutor;
+        this.scheduledExecutorService = scheduledExecutorService;
+        this.channelizer = channelizer;
+        this.sessionExecutor = gremlinExecutor.getExecutorService();
+    }
+
+    @Override
+    protected void channelRead0(final ChannelHandlerContext ctx, final RequestMessage msg) throws Exception {
+        try {
+            try {
+                validateRequest(msg, graphManager);
+            } catch (SessionException we) {
+                ctx.writeAndFlush(we.getResponseMessage());
+                return;
+            }
+
+            final Optional<String> optMultiTaskSession = msg.optionalArgs(Tokens.ARGS_SESSION);
+            final String sessionId = optMultiTaskSession.orElse(msg.getRequestId().toString());
+
+            // the SessionTask is really a Context from OpProcessor. we still need the GremlinExecutor/ScriptEngine
+            // config that is all rigged up into the server nicely right now so it seemed best to just keep the general
+            // Context object but extend (essentially rename) it to SessionTask so that it better fits the nomenclature
+            // we have here. when we drop OpProcessor stuff and rid ourselves of GremlinExecutor then we can probably
+            // pare down the constructor for SessionTask further.
+            final SessionTask sessionTask = new SessionTask(msg, ctx, settings, graphManager,
+                    gremlinExecutor, scheduledExecutorService);
+
+            if (sessions.containsKey(sessionId)) {
+                final Session session = sessions.get(sessionId);
+
+                // check if the session is bound to this channel, thus one client per session
+                if (!session.isBoundTo(ctx.channel())) {
+                    final String sessionClosedMessage = String.format("Session %s is not bound to the connecting client", sessionId);
+                    final ResponseMessage response = ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR)
+                            .statusMessage(sessionClosedMessage).create();
+                    ctx.writeAndFlush(response);
+                    return;
+                }
+
+                // if the session is done accepting tasks then error time
+                if (session.isAcceptingTasks() && !session.submitTask(sessionTask)) {
+                    final String sessionClosedMessage = String.format(
+                            "Session %s is no longer accepting requests as it has been closed", sessionId);
+                    final ResponseMessage response = ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR)
+                            .statusMessage(sessionClosedMessage).create();
+                    ctx.writeAndFlush(response);
+                }
+            } else {
+                // determine the type of session to start - one that processes the current request only and close OR
+                // one that will process this current request and ones that may arrive in the future.
+                final Session session = optMultiTaskSession.isPresent() ?
+                        createMultiTaskSession(sessionTask, sessionId) :
+                        createSingleTaskSession(sessionTask, sessionId);
+
+                // queue the session to startup when a thread is ready to take it
+                final Future<?> sessionFuture = sessionExecutor.submit(session);
+                session.setSessionFuture(sessionFuture);
+                sessions.put(sessionId, session);
+
+                // determine the max session life. for multi that's going to be "session life" and for single that
+                // will be the span of the request timeout
+                final long seto = sessionTask.getRequestTimeout();
+                final long sessionLife = optMultiTaskSession.isPresent() ? settings.sessionLifetimeTimeout : seto;
+
+                // if timeout is enabled when greater than zero schedule up a timeout which is a session life timeout
+                // for a multi or technically a request timeout for a single. this will be cancelled when the session
+                // closes by way of other reasons (i.e. success or exception) - see AbstractSession#close()
+                if (seto > 0) {
+                    final ScheduledFuture<?> sessionCancelFuture =
+                            scheduledExecutorService.schedule(
+                                    () -> session.triggerTimeout(sessionLife, optMultiTaskSession.isPresent()),
+                                    sessionLife, TimeUnit.MILLISECONDS);
+                    session.setSessionCancelFuture(sessionCancelFuture);
+                }
+            }
+        } catch (RejectedExecutionException ree) {
+            logger.warn(ree.getMessage());
+
+            // generic message seems ok here? like, you would know what you were submitting on, i.e. session or
+            // sessionless, when you got this error. probably don't need gory details.
+            final ResponseMessage response = ResponseMessage.build(msg).code(ResponseStatusCode.TOO_MANY_REQUESTS)
+                    .statusMessage("Rate limiting").create();
+            ctx.writeAndFlush(response);
+        } finally {
+            ReferenceCountUtil.release(msg);
+        }
+    }
+
+    protected void validateRequest(final RequestMessage message, final GraphManager graphManager) throws SessionException {
+        if (!message.optionalArgs(Tokens.ARGS_GREMLIN).isPresent()) {
+            final String msg = String.format("A message with an [%s] op code requires a [%s] argument.", message.getOp(), Tokens.ARGS_GREMLIN);
+            throw new SessionException(msg, ResponseMessage.build(message).code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(msg).create());
+        }
+
+        if (message.optionalArgs(Tokens.ARGS_SESSION).isPresent()) {
+            final Optional<Object> mtx = message.optionalArgs(Tokens.ARGS_MANAGE_TRANSACTION);
+            if (mtx.isPresent() && !(mtx.get() instanceof Boolean)) {
+                final String msg = String.format("%s argument must be of type boolean", Tokens.ARGS_MANAGE_TRANSACTION);
+                throw new SessionException(msg, ResponseMessage.build(message).code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(msg).create());
+            }
+
+            final Optional<Object> msae = message.optionalArgs(Tokens.ARGS_MAINTAIN_STATE_AFTER_EXCEPTION);
+            if (msae.isPresent() && !(msae.get() instanceof Boolean)) {
+                final String msg = String.format("%s argument must be of type boolean", Tokens.ARGS_MAINTAIN_STATE_AFTER_EXCEPTION);
+                throw new SessionException(msg, ResponseMessage.build(message).code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(msg).create());
+            }
+        } else {
+            if (message.optionalArgs(Tokens.ARGS_MANAGE_TRANSACTION).isPresent()) {
+                final String msg = String.format("%s argument only applies to requests made for sessions", Tokens.ARGS_MANAGE_TRANSACTION);
+                throw new SessionException(msg, ResponseMessage.build(message).code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(msg).create());
+            }
+
+            if (message.optionalArgs(Tokens.ARGS_MAINTAIN_STATE_AFTER_EXCEPTION).isPresent()) {
+                final String msg = String.format("%s argument only applies to requests made for sessions", Tokens.ARGS_MAINTAIN_STATE_AFTER_EXCEPTION);
+                throw new SessionException(msg, ResponseMessage.build(message).code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(msg).create());
+            }
+        }
+
+        if (message.optionalArgs(Tokens.ARGS_BINDINGS).isPresent()) {
+            final Map bindings = (Map) message.getArgs().get(Tokens.ARGS_BINDINGS);
+            if (IteratorUtils.anyMatch(bindings.keySet().iterator(), k -> null == k || !(k instanceof String))) {
+                final String msg = String.format("The [%s] message is using one or more invalid binding keys - they must be of type String and cannot be null", Tokens.OPS_EVAL);
+                throw new SessionException(msg, ResponseMessage.build(message).code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(msg).create());
+            }
+
+            final Set<String> badBindings = IteratorUtils.set(IteratorUtils.<String>filter(bindings.keySet().iterator(), INVALID_BINDINGS_KEYS::contains));
+            if (!badBindings.isEmpty()) {
+                final String msg = String.format("The [%s] message supplies one or more invalid parameters key of [%s] - these are reserved names.", Tokens.OPS_EVAL, badBindings);
+                throw new SessionException(msg, ResponseMessage.build(message).code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(msg).create());
+            }
+
+            // ignore control bindings that get passed in with the "#jsr223" prefix - those aren't used in compilation
+            if (IteratorUtils.count(IteratorUtils.filter(bindings.keySet().iterator(), k -> !k.toString().startsWith("#jsr223"))) > settings.maxParameters) {
+                final String msg = String.format("The [%s] message contains %s bindings which is more than is allowed by the server %s configuration",
+                        Tokens.OPS_EVAL, bindings.size(), settings.maxParameters);
+                throw new SessionException(msg, ResponseMessage.build(message).code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(msg).create());
+            }
+        }
+
+        // validations for specific op codes
+        if (message.getOp().equals(Tokens.OPS_EVAL)) {
+            // eval must have gremlin that is type of String
+            // likely a problem with the driver and how it is sending requests
+            if (!(message.optionalArgs(Tokens.ARGS_GREMLIN).get() instanceof String)) {
+                final String msg = String.format("A message with [%s] op code requires a [%s] argument that is of type %s.",
+                        Tokens.OPS_EVAL, Tokens.ARGS_GREMLIN, String.class.getSimpleName());
+                throw new SessionException(msg, ResponseMessage.build(message).code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(msg).create());
+            }
+        } else if (message.getOp().equals(Tokens.OPS_BYTECODE)) {
+            // bytecode should have gremlin that is of type Bytecode
+            // likely a problem with the driver and how it is sending requests
+            if (!(message.optionalArgs(Tokens.ARGS_GREMLIN).get() instanceof Bytecode)) {
+                final String msg = String.format("A message with [%s] op code requires a [%s] argument that is of type %s.",
+                        Tokens.OPS_BYTECODE, Tokens.ARGS_GREMLIN, Bytecode.class.getSimpleName());
+                throw new SessionException(msg, ResponseMessage.build(message).code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(msg).create());
+            }
+
+            // bytecode should have an alias bound
+            final Optional<Map<String, String>> aliases = message.optionalArgs(Tokens.ARGS_ALIASES);
+            if (!aliases.isPresent()) {
+                final String msg = String.format("A message with [%s] op code requires a [%s] argument.", Tokens.OPS_BYTECODE, Tokens.ARGS_ALIASES);
+                throw new SessionException(msg, ResponseMessage.build(message).code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(msg).create());
+            }
+
+            if (aliases.get().size() != 1 || !aliases.get().containsKey(Tokens.VAL_TRAVERSAL_SOURCE_ALIAS)) {
+                final String msg = String.format("A message with [%s] op code requires the [%s] argument to be a Map containing one alias assignment named '%s'.",
+                        Tokens.OPS_BYTECODE, Tokens.ARGS_ALIASES, Tokens.VAL_TRAVERSAL_SOURCE_ALIAS);
+                throw new SessionException(msg, ResponseMessage.build(message).code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(msg).create());
+            }
+
+            final String traversalSourceBindingForAlias = aliases.get().values().iterator().next();
+            if (!graphManager.getTraversalSourceNames().contains(traversalSourceBindingForAlias)) {
+                final String msg = String.format("The traversal source [%s] for alias [%s] is not configured on the server.", traversalSourceBindingForAlias, Tokens.VAL_TRAVERSAL_SOURCE_ALIAS);
+                throw new SessionException(msg, ResponseMessage.build(message).code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(msg).create());
+            }
+        }
+    }
+
+    @Override
+    public void userEventTriggered(final ChannelHandlerContext ctx, final Object evt) throws Exception {
+        // only need to handle this event if the idle monitor is on
+        if (!channelizer.supportsIdleMonitor()) return;
+
+        if (evt instanceof IdleStateEvent) {
+            final IdleStateEvent e = (IdleStateEvent) evt;
+
+            // if no requests (reader) then close, if no writes from server to client then ping. clients should
+            // periodically ping the server, but coming from this direction allows the server to kill channels that
+            // have dead clients on the other end
+            if (e.state() == IdleState.READER_IDLE) {
+                logger.info("Closing channel - client is disconnected after idle period of " + settings.idleConnectionTimeout + " " + ctx.channel().id().asShortText());
+                ctx.close();
+            } else if (e.state() == IdleState.WRITER_IDLE && settings.keepAliveInterval > 0) {
+                logger.info("Checking channel - sending ping to client after idle period of " + settings.keepAliveInterval + " " + ctx.channel().id().asShortText());
+                ctx.writeAndFlush(channelizer.createIdleDetectionMessage());
+            }
+        }
+    }
+
+    /**
+     * Called when creating a single task session where the provided {@link SessionTask} will be the only one to be
+     * executed and can therefore take a more efficient execution path.
+     */
+    protected Session createSingleTaskSession(final SessionTask sessionTask, final String sessionId) {
+        return new SingleTaskSession(sessionTask, sessionId, sessions);
+    }
+
+    /**
+     * Called when creating a {@link Session} that will be long-lived to extend over multiple requests and therefore
+     * process the provided {@link SessionTask} as well as ones that may arrive in the future.
+     */
+    protected Session createMultiTaskSession(final SessionTask sessionTask, final String sessionId) {
+        return new MultiTaskSession(sessionTask, sessionId, sessions);
+    }
+
+    public boolean isActiveSession(final String sessionId) {
+        return sessions.containsKey(sessionId);
+    }
+
+    public int getActiveSessionCount() {
+        return sessions.size();
+    }
+}
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/WebSocketAuthorizationHandler.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/WebSocketAuthorizationHandler.java
new file mode 100644
index 0000000..98a2411
--- /dev/null
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/WebSocketAuthorizationHandler.java
@@ -0,0 +1,109 @@
+/*
+ * 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.server.handler;
+
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+
+import org.apache.tinkerpop.gremlin.driver.Tokens;
+import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
+import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
+import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
+import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
+import org.apache.tinkerpop.gremlin.server.GremlinServer;
+import org.apache.tinkerpop.gremlin.server.auth.AuthenticatedUser;
+import org.apache.tinkerpop.gremlin.server.authz.Authorizer;
+import org.apache.tinkerpop.gremlin.server.authz.AuthorizationException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Map;
+
+
+/**
+ *  An authorization handler for the websockets channel that allows the {@link Authorizer} to be plugged into it.
+ *
+ * @author Marc de Lignie
+ */
+@ChannelHandler.Sharable
+public class WebSocketAuthorizationHandler extends ChannelInboundHandlerAdapter {
+    private static final Logger logger = LoggerFactory.getLogger(WebSocketAuthorizationHandler.class);
+    private static final Logger auditLogger = LoggerFactory.getLogger(GremlinServer.AUDIT_LOGGER_NAME);
+
+    private AuthenticatedUser user;
+    private final Authorizer authorizer;
+
+    public WebSocketAuthorizationHandler(Authorizer authorizer) {
+        this.authorizer = authorizer;
+    }
+
+    @Override
+    public void channelRead(final ChannelHandlerContext ctx, final Object msg) {
+        if (msg instanceof RequestMessage){
+            final RequestMessage requestMessage = (RequestMessage) msg;
+            try {
+                user = ctx.channel().attr(StateKey.AUTHENTICATED_USER).get();
+                if (null == user) {    // This is expected when using the AllowAllAuthenticator
+                    user = AuthenticatedUser.ANONYMOUS_USER;
+                }
+                switch (requestMessage.getOp()) {
+                    case Tokens.OPS_BYTECODE:
+                        final Bytecode bytecode = (Bytecode) requestMessage.getArgs().get(Tokens.ARGS_GREMLIN);
+                        final Map<String, String> aliases = (Map<String, String>) requestMessage.getArgs().get(Tokens.ARGS_ALIASES);
+                        final Bytecode restrictedBytecode = authorizer.authorize(user, bytecode, aliases);
+                        final RequestMessage restrictedMsg = RequestMessage.build(Tokens.OPS_BYTECODE).
+                                overrideRequestId(requestMessage.getRequestId()).
+                                processor("traversal").
+                                addArg(Tokens.ARGS_GREMLIN, restrictedBytecode).
+                                addArg(Tokens.ARGS_ALIASES, aliases).create();
+                        ctx.fireChannelRead(restrictedMsg);
+                        break;
+                    case Tokens.OPS_EVAL:
+                        authorizer.authorize(user, requestMessage);
+                        ctx.fireChannelRead(requestMessage);
+                        break;
+                    default:
+                        throw new AuthorizationException("This AuthorizationHandler only handles requests with OPS_BYTECODE or OPS_EVAL.");
+                }
+            } catch (AuthorizationException ex) {  // Expected: users can alternate between allowed and disallowed requests
+                String address = ctx.channel().remoteAddress().toString();
+                if (address.startsWith("/") && address.length() > 1) address = address.substring(1);
+                auditLogger.info("User {} with address {} attempted an unauthorized request for {} operation: {}",
+                        user.getName(), address, requestMessage.getOp(), requestMessage.getArgs().get(Tokens.ARGS_GREMLIN));
+                interruptEvaluation(ctx, requestMessage, ex.getMessage());
+            } catch (Exception ex) {
+                logger.error("{} is not ready to handle requests - unknown error",
+                    authorizer.getClass().getSimpleName());
+                interruptEvaluation(ctx, requestMessage, "Unknown error in gremlin-server");
+            }
+        } else {
+            logger.warn("{} only processes RequestMessage instances - received {} - channel closing",
+                this.getClass().getSimpleName(), msg.getClass());
+            ctx.close();
+        }
+    }
+
+    private void interruptEvaluation(final ChannelHandlerContext ctx, final RequestMessage requestMessage, final String errorMessage) {
+        final ResponseMessage error = ResponseMessage.build(requestMessage)
+            .statusMessage("Failed to authorize: " + errorMessage)
+            .code(ResponseStatusCode.UNAUTHORIZED).create();
+        ctx.writeAndFlush(error);
+    }
+}
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/WsAndHttpChannelizerHandler.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/WsAndHttpChannelizerHandler.java
index e4f79b4..398dca1 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/WsAndHttpChannelizerHandler.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/WsAndHttpChannelizerHandler.java
@@ -28,9 +28,9 @@
 import org.apache.tinkerpop.gremlin.server.channel.WsAndHttpChannelizer;
 import org.apache.tinkerpop.gremlin.server.util.ServerGremlinExecutor;
 
+import static org.apache.tinkerpop.gremlin.server.AbstractChannelizer.PIPELINE_HTTP_AGGREGATOR;
 import static org.apache.tinkerpop.gremlin.server.channel.WebSocketChannelizer.PIPELINE_AUTHENTICATOR;
 import static org.apache.tinkerpop.gremlin.server.channel.WebSocketChannelizer.PIPELINE_REQUEST_HANDLER;
-import static org.apache.tinkerpop.gremlin.server.channel.WebSocketChannelizer.PIPELINE_HTTP_RESPONSE_ENCODER;
 
 /**
  * A ChannelInboundHandlerAdapter for use with {@link WsAndHttpChannelizer} that toggles between WebSockets
@@ -62,15 +62,28 @@
     public void channelRead(final ChannelHandlerContext ctx, final Object obj) {
         final ChannelPipeline pipeline = ctx.pipeline();
         if (obj instanceof HttpMessage && !WebSocketHandlerUtil.isWebSocket((HttpMessage)obj)) {
+            // if the message is for HTTP and not websockets then this handler injects the endpoint handler in front
+            // of the HTTP Aggregator to intercept the HttpMessage. Therefore the pipeline looks like this at start:
+            //
+            // IdleStateHandler -> HttpResponseEncoder -> HttpRequestDecoder ->
+            //    WsAndHttpChannelizerHandler -> HttpObjectAggregator ->
+            //    WebSocketServerCompressionHandler -> WebSocketServerProtocolHandshakeHandler -> (more websockets)
+            //
+            // and shifts to (setting aside the authentication condition):
+            //
+            // IdleStateHandler -> HttpResponseEncoder -> HttpRequestDecoder ->
+            //    WsAndHttpChannelizerHandler -> HttpObjectAggregator ->
+            //    HttpGremlinEndpointHandler ->
+            //    WebSocketServerCompressionHandler - WebSocketServerProtocolHandshakeHandler -> (more websockets)
             if (null != pipeline.get(PIPELINE_AUTHENTICATOR)) {
                 pipeline.remove(PIPELINE_REQUEST_HANDLER);
                 final ChannelHandler authenticator = pipeline.get(PIPELINE_AUTHENTICATOR);
                 pipeline.remove(PIPELINE_AUTHENTICATOR);
-                pipeline.addAfter(PIPELINE_HTTP_RESPONSE_ENCODER, PIPELINE_AUTHENTICATOR, authenticator);
+                pipeline.addAfter(PIPELINE_HTTP_AGGREGATOR, PIPELINE_AUTHENTICATOR, authenticator);
                 pipeline.addAfter(PIPELINE_AUTHENTICATOR, PIPELINE_REQUEST_HANDLER, this.httpGremlinEndpointHandler);
             } else {
                 pipeline.remove(PIPELINE_REQUEST_HANDLER);
-                pipeline.addAfter(PIPELINE_HTTP_RESPONSE_ENCODER, PIPELINE_REQUEST_HANDLER, this.httpGremlinEndpointHandler);
+                pipeline.addAfter(PIPELINE_HTTP_AGGREGATOR, PIPELINE_REQUEST_HANDLER, this.httpGremlinEndpointHandler);
             }
         }
         ctx.fireChannelRead(obj);
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/WsGremlinBinaryRequestDecoder.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/WsGremlinBinaryRequestDecoder.java
index a56d017..b05ae92 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/WsGremlinBinaryRequestDecoder.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/WsGremlinBinaryRequestDecoder.java
@@ -45,9 +45,9 @@
     private static final Logger logger = LoggerFactory.getLogger(WsGremlinBinaryRequestDecoder.class);
 
     private static final Charset UTF8 = Charset.forName("UTF-8");
-    private final Map<String, MessageSerializer> serializers;
+    private final Map<String, MessageSerializer<?>> serializers;
 
-    public WsGremlinBinaryRequestDecoder(final Map<String, MessageSerializer> serializers) {
+    public WsGremlinBinaryRequestDecoder(final Map<String, MessageSerializer<?>> serializers) {
         this.serializers = serializers;
     }
 
@@ -64,7 +64,7 @@
         try {
             messageBytes.readBytes(contentTypeBytes);
             final String contentType = contentTypeBytes.toString(UTF8);
-            final MessageSerializer serializer = select(contentType, ServerSerializers.DEFAULT_SERIALIZER);
+            final MessageSerializer<?> serializer = select(contentType, ServerSerializers.DEFAULT_BINARY_SERIALIZER);
 
             // it's important to re-initialize these channel attributes as they apply globally to the channel. in
             // other words, the next request to this channel might not come with the same configuration and mixed
@@ -83,7 +83,7 @@
         }
     }
 
-    private MessageSerializer select(final String mimeType, final MessageSerializer defaultSerializer) {
+    private MessageSerializer<?> select(final String mimeType, final MessageSerializer<?> defaultSerializer) {
         if (logger.isWarnEnabled() && !serializers.containsKey(mimeType))
             logger.warn("Gremlin Server is not configured with a serializer for the requested mime type [{}] - using {} by default",
                     mimeType, defaultSerializer.getClass().getName());
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/WsGremlinCloseRequestDecoder.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/WsGremlinCloseRequestDecoder.java
index 8567ff0..c9a48c6 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/WsGremlinCloseRequestDecoder.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/WsGremlinCloseRequestDecoder.java
@@ -26,7 +26,6 @@
 import org.apache.tinkerpop.gremlin.driver.MessageSerializer;
 import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
 import org.apache.tinkerpop.gremlin.driver.ser.SerializationException;
-import org.apache.tinkerpop.gremlin.driver.ser.Serializers;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -45,9 +44,9 @@
     private static final Logger logger = LoggerFactory.getLogger(WsGremlinCloseRequestDecoder.class);
 
     private static final Charset UTF8 = Charset.forName("UTF-8");
-    private final Map<String, MessageSerializer> serializers;
+    private final Map<String, MessageSerializer<?>> serializers;
 
-    public WsGremlinCloseRequestDecoder(final Map<String, MessageSerializer> serializers) {
+    public WsGremlinCloseRequestDecoder(final Map<String, MessageSerializer<?>> serializers) {
         this.serializers = serializers;
     }
 
@@ -64,7 +63,7 @@
         try {
             messageBytes.readBytes(contentTypeBytes);
             final String contentType = contentTypeBytes.toString(UTF8);
-            final MessageSerializer serializer = select(contentType, ServerSerializers.DEFAULT_SERIALIZER);
+            final MessageSerializer<?> serializer = select(contentType, ServerSerializers.DEFAULT_BINARY_SERIALIZER);
 
             // it's important to re-initialize these channel attributes as they apply globally to the channel. in
             // other words, the next request to this channel might not come with the same configuration and mixed
@@ -83,7 +82,7 @@
         }
     }
 
-    private MessageSerializer select(final String mimeType, final MessageSerializer defaultSerializer) {
+    private MessageSerializer<?> select(final String mimeType, final MessageSerializer<?> defaultSerializer) {
         if (logger.isWarnEnabled() && !serializers.containsKey(mimeType))
             logger.warn("Gremlin Server is not configured with a serializer for the requested mime type [{}] - using {} by default",
                     mimeType, defaultSerializer.getClass().getName());
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/WsGremlinTextRequestDecoder.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/WsGremlinTextRequestDecoder.java
index 0f614ca..50dc6f3 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/WsGremlinTextRequestDecoder.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/WsGremlinTextRequestDecoder.java
@@ -42,9 +42,9 @@
 public class WsGremlinTextRequestDecoder extends MessageToMessageDecoder<TextWebSocketFrame> {
     private static final Logger logger = LoggerFactory.getLogger(WsGremlinTextRequestDecoder.class);
 
-    private final Map<String, MessageSerializer> serializers;
+    private final Map<String, MessageSerializer<?>> serializers;
 
-    public WsGremlinTextRequestDecoder(final Map<String, MessageSerializer> serializers) {
+    public WsGremlinTextRequestDecoder(final Map<String, MessageSerializer<?>> serializers) {
         this.serializers = serializers;
     }
 
@@ -52,7 +52,7 @@
     protected void decode(final ChannelHandlerContext channelHandlerContext, final TextWebSocketFrame frame, final List<Object> objects) throws Exception {
         try {
             // the default serializer must be a MessageTextSerializer instance to be compatible with this decoder
-            final MessageTextSerializer serializer = (MessageTextSerializer) select("application/json", ServerSerializers.DEFAULT_SERIALIZER);
+            final MessageTextSerializer<?> serializer = (MessageTextSerializer<?>) select("application/json", ServerSerializers.DEFAULT_TEXT_SERIALIZER);
 
             // it's important to re-initialize these channel attributes as they apply globally to the channel. in
             // other words, the next request to this channel might not come with the same configuration and mixed
@@ -67,7 +67,7 @@
         }
     }
 
-    private MessageSerializer select(final String mimeType, final MessageSerializer defaultSerializer) {
+    private MessageSerializer<?> select(final String mimeType, final MessageSerializer<?> defaultSerializer) {
         if (logger.isWarnEnabled() && !serializers.containsKey(mimeType))
             logger.warn("Gremlin Server is not configured with a serializer for the requested mime type [{}] - using {} by default",
                     mimeType, defaultSerializer.getClass().getName());
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/AbstractEvalOpProcessor.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/AbstractEvalOpProcessor.java
index 2620e47..fbb42f5 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/AbstractEvalOpProcessor.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/AbstractEvalOpProcessor.java
@@ -30,7 +30,8 @@
 import org.apache.tinkerpop.gremlin.process.traversal.Pop;
 import org.apache.tinkerpop.gremlin.process.traversal.Scope;
 import org.apache.tinkerpop.gremlin.server.OpProcessor;
-import org.apache.tinkerpop.gremlin.server.ResponseHandlerContext;
+import org.apache.tinkerpop.gremlin.server.auth.AuthenticatedUser;
+import org.apache.tinkerpop.gremlin.server.handler.StateKey;
 import org.apache.tinkerpop.gremlin.structure.Column;
 import org.apache.tinkerpop.gremlin.structure.T;
 import org.apache.tinkerpop.gremlin.server.Context;
@@ -52,6 +53,7 @@
 import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.RejectedExecutionException;
 import java.util.concurrent.TimeoutException;
 import java.util.function.Supplier;
 
@@ -134,7 +136,7 @@
      * handled will be passed to this method to see if the sub-class can service the requested op code.
      * @return
      */
-    public abstract Optional<ThrowingConsumer<Context>> selectOther(final RequestMessage requestMessage) throws OpProcessorException;
+    public abstract Optional<ThrowingConsumer<Context>> selectOther(final Context ctx) throws OpProcessorException;
 
     @Override
     public ThrowingConsumer<Context> select(final Context ctx) throws OpProcessorException {
@@ -150,7 +152,7 @@
                 final String msgInvalid = String.format("Message could not be parsed.  Check the format of the request. [%s]", message);
                 throw new OpProcessorException(msgInvalid, ResponseMessage.build(message).code(ResponseStatusCode.REQUEST_ERROR_MALFORMED_REQUEST).statusMessage(msgInvalid).create());
             default:
-                op = selectOther(message).orElseThrow(() -> {
+                op = selectOther(ctx).orElseThrow(() -> {
                     final String msgDefault = String.format("Message with op code [%s] is not recognized.", message.getOp());
                     return new OpProcessorException(msgDefault, ResponseMessage.build(message).code(ResponseStatusCode.REQUEST_ERROR_MALFORMED_REQUEST).statusMessage(msgDefault).create());
                 });
@@ -190,15 +192,6 @@
     }
 
     /**
-     * @deprecated As of release 3.3.8, replaced by {@link #evalOpInternal(Context, Supplier, BindingSupplier)}.
-     */
-    @Deprecated
-    protected void evalOpInternal(final ResponseHandlerContext ctx, final Supplier<GremlinExecutor> gremlinExecutorSupplier,
-                                  final BindingSupplier bindingsSupplier) throws OpProcessorException {
-        evalOpInternal(ctx.getContext(), gremlinExecutorSupplier, bindingsSupplier);
-    }
-
-    /**
      * A generalized implementation of the "eval" operation.  It handles script evaluation and iteration of results
      * so as to write {@link ResponseMessage} objects down the Netty pipeline.  It also handles script timeouts,
      * iteration timeouts, metrics and building bindings.  Note that result iteration is delegated to the
@@ -212,7 +205,7 @@
  *                         {@link GremlinExecutor#eval} method.
      */
     protected void evalOpInternal(final Context ctx, final Supplier<GremlinExecutor> gremlinExecutorSupplier,
-                                  final BindingSupplier bindingsSupplier) throws OpProcessorException {
+                                  final BindingSupplier bindingsSupplier) {
         final Timer.Context timerContext = evalOpTimer.time();
         final RequestMessage msg = ctx.getRequestMessage();
         final GremlinExecutor gremlinExecutor = gremlinExecutorSupplier.get();
@@ -230,11 +223,8 @@
 
         // timeout override - handle both deprecated and newly named configuration. earlier logic should prevent
         // both configurations from being submitted at the same time
-        final long seto = args.containsKey(Tokens.ARGS_SCRIPT_EVAL_TIMEOUT) || args.containsKey(Tokens.ARGS_EVAL_TIMEOUT)
-            // could be sent as an integer or long
-            ? (args.containsKey(Tokens.ARGS_SCRIPT_EVAL_TIMEOUT) ?
-                ((Number) args.get(Tokens.ARGS_SCRIPT_EVAL_TIMEOUT)).longValue() : ((Number) args.get(Tokens.ARGS_EVAL_TIMEOUT)).longValue())
-            : settings.getEvaluationTimeout();
+        final long seto = args.containsKey(Tokens.ARGS_EVAL_TIMEOUT) ?
+                ((Number) args.get(Tokens.ARGS_EVAL_TIMEOUT)).longValue() : settings.getEvaluationTimeout();
 
         final GremlinExecutor.LifeCycle lifeCycle = GremlinExecutor.LifeCycle.build()
                 .evaluationTimeoutOverride(seto)
@@ -254,6 +244,15 @@
                     final Iterator itty = IteratorUtils.asIterator(o);
 
                     logger.debug("Preparing to iterate results from - {} - in thread [{}]", msg, Thread.currentThread().getName());
+                    if (settings.enableAuditLog) {
+                        AuthenticatedUser user = ctx.getChannelHandlerContext().channel().attr(StateKey.AUTHENTICATED_USER).get();
+                        if (null == user) {    // This is expected when using the AllowAllAuthenticator
+                            user = AuthenticatedUser.ANONYMOUS_USER;
+                        }
+                        String address = ctx.getChannelHandlerContext().channel().remoteAddress().toString();
+                        if (address.startsWith("/") && address.length() > 1) address = address.substring(1);
+                        auditLogger.info("User {} with address {} requested: {}", user.getName(), address, script);
+                    }
                     if (settings.authentication.enableAuditLog) {
                         String address = ctx.getChannelHandlerContext().channel().remoteAddress().toString();
                         if (address.startsWith("/") && address.length() > 1) address = address.substring(1);
@@ -271,53 +270,65 @@
                     }
                 }).create();
 
-        final CompletableFuture<Object> evalFuture = gremlinExecutor.eval(script, language, bindings, lifeCycle);
+        try {
+            final CompletableFuture<Object> evalFuture = gremlinExecutor.eval(script, language, bindings, lifeCycle);
 
-        evalFuture.handle((v, t) -> {
-            timerContext.stop();
+            evalFuture.handle((v, t) -> {
+                timerContext.stop();
 
-            if (t != null) {
-                if (t instanceof OpProcessorException) {
-                    ctx.writeAndFlush(((OpProcessorException) t).getResponseMessage());
-                } else if (t instanceof TimedInterruptTimeoutException) {
-                    // occurs when the TimedInterruptCustomizerProvider is in play
-                    final String errorMessage = String.format("A timeout occurred within the script during evaluation of [%s] - consider increasing the limit given to TimedInterruptCustomizerProvider", msg);
-                    logger.warn(errorMessage);
-                    ctx.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR_TIMEOUT)
-                                                     .statusMessage("Timeout during script evaluation triggered by TimedInterruptCustomizerProvider")
-                                                     .statusAttributeException(t).create());
-                } else if (t instanceof TimeoutException) {
-                    final String errorMessage = String.format("Script evaluation exceeded the configured threshold for request [%s]", msg);
-                    logger.warn(errorMessage, t);
-                    ctx.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR_TIMEOUT)
-                                                     .statusMessage(t.getMessage())
-                                                     .statusAttributeException(t).create());
-                } else {
-                    // try to trap the specific jvm error of "Method code too large!" to re-write it as something nicer,
-                    // but only re-write if it's the only error because otherwise we might lose some other important
-                    // information related to the failure. at this point, there hasn't been a scenario that has
-                    // presented itself where the "Method code too large!" comes with other compilation errors so
-                    // it seems that this message trumps other compilation errors to some reasonable degree that ends
-                    // up being favorable for this problem
-                    if (t instanceof MultipleCompilationErrorsException && t.getMessage().contains("Method too large") &&
-                            ((MultipleCompilationErrorsException) t).getErrorCollector().getErrorCount() == 1) {
-                        final String errorMessage = String.format("The Gremlin statement that was submitted exceeds the maximum compilation size allowed by the JVM, please split it into multiple smaller statements - %s", trimMessage(msg));
+                if (t != null) {
+                    // if any exception in the chain is TemporaryException then we should respond with the right error
+                    // code so that the client knows to retry
+                    final Optional<Throwable> possibleTemporaryException = determineIfTemporaryException(t);
+                    if (possibleTemporaryException.isPresent()) {
+                        ctx.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR_TEMPORARY)
+                                .statusMessage(possibleTemporaryException.get().getMessage())
+                                .statusAttributeException(possibleTemporaryException.get()).create());
+                    } else if (t instanceof OpProcessorException) {
+                        ctx.writeAndFlush(((OpProcessorException) t).getResponseMessage());
+                    } else if (t instanceof TimedInterruptTimeoutException) {
+                        // occurs when the TimedInterruptCustomizerProvider is in play
+                        final String errorMessage = String.format("A timeout occurred within the script during evaluation of [%s] - consider increasing the limit given to TimedInterruptCustomizerProvider", msg);
                         logger.warn(errorMessage);
-                        ctx.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR_SCRIPT_EVALUATION)
-                                                         .statusMessage(errorMessage)
-                                                         .statusAttributeException(t).create());
+                        ctx.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR_TIMEOUT)
+                                .statusMessage("Timeout during script evaluation triggered by TimedInterruptCustomizerProvider")
+                                .statusAttributeException(t).create());
+                    } else if (t instanceof TimeoutException) {
+                        final String errorMessage = String.format("Script evaluation exceeded the configured threshold for request [%s]", msg);
+                        logger.warn(errorMessage, t);
+                        ctx.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR_TIMEOUT)
+                                .statusMessage(t.getMessage())
+                                .statusAttributeException(t).create());
                     } else {
-                        final String errorMessage =  (t.getMessage() == null) ? t.toString() : t.getMessage();
-                        logger.warn(String.format("Exception processing a script on request [%s].", msg), t);
-                        ctx.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR_SCRIPT_EVALUATION)
-                                                         .statusMessage(errorMessage)
-                                                         .statusAttributeException(t).create());
+                        // try to trap the specific jvm error of "Method code too large!" to re-write it as something nicer,
+                        // but only re-write if it's the only error because otherwise we might lose some other important
+                        // information related to the failure. at this point, there hasn't been a scenario that has
+                        // presented itself where the "Method code too large!" comes with other compilation errors so
+                        // it seems that this message trumps other compilation errors to some reasonable degree that ends
+                        // up being favorable for this problem
+                        if (t instanceof MultipleCompilationErrorsException && t.getMessage().contains("Method too large") &&
+                                ((MultipleCompilationErrorsException) t).getErrorCollector().getErrorCount() == 1) {
+                            final String errorMessage = String.format("The Gremlin statement that was submitted exceeds the maximum compilation size allowed by the JVM, please split it into multiple smaller statements - %s", trimMessage(msg));
+                            logger.warn(errorMessage);
+                            ctx.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR_EVALUATION)
+                                    .statusMessage(errorMessage)
+                                    .statusAttributeException(t).create());
+                        } else {
+                            final String errorMessage = (t.getMessage() == null) ? t.toString() : t.getMessage();
+                            logger.warn(String.format("Exception processing a script on request [%s].", msg), t);
+                            ctx.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR_EVALUATION)
+                                    .statusMessage(errorMessage)
+                                    .statusAttributeException(t).create());
+                        }
                     }
                 }
-            }
 
-            return null;
-        });
+                return null;
+            });
+        } catch (RejectedExecutionException ree) {
+            ctx.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.TOO_MANY_REQUESTS)
+                    .statusMessage("Rate limiting").create());
+        }
     }
 
     /**
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/AbstractOpProcessor.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/AbstractOpProcessor.java
index 8c7ec55..1498c51 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/AbstractOpProcessor.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/AbstractOpProcessor.java
@@ -19,6 +19,7 @@
 package org.apache.tinkerpop.gremlin.server.op;
 
 import io.netty.channel.ChannelHandlerContext;
+import org.apache.commons.lang3.exception.ExceptionUtils;
 import org.apache.tinkerpop.gremlin.driver.MessageSerializer;
 import org.apache.tinkerpop.gremlin.driver.Tokens;
 import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
@@ -28,11 +29,11 @@
 import org.apache.tinkerpop.gremlin.server.Context;
 import org.apache.tinkerpop.gremlin.server.GraphManager;
 import org.apache.tinkerpop.gremlin.server.OpProcessor;
-import org.apache.tinkerpop.gremlin.server.ResponseHandlerContext;
 import org.apache.tinkerpop.gremlin.server.Settings;
 import org.apache.tinkerpop.gremlin.server.handler.Frame;
 import org.apache.tinkerpop.gremlin.server.handler.StateKey;
 import org.apache.tinkerpop.gremlin.server.util.ExceptionHelper;
+import org.apache.tinkerpop.gremlin.structure.util.TemporaryException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -43,7 +44,9 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Stream;
 
 /**
  * A base {@link OpProcessor} implementation that processes an {@code Iterator} of results in a generalized way while
@@ -64,11 +67,12 @@
     }
 
     /**
-     * @deprecated As of release 3.3.8, not replaced.
+     * Check if any exception in the chain is TemporaryException then we should respond with the right error code so
+     * that the client knows to retry.
      */
-    @Deprecated
-    protected void handleIterator(final ResponseHandlerContext rhc, final Iterator itty) throws InterruptedException {
-        handleIterator(rhc.getContext(), itty);
+    protected static Optional<Throwable> determineIfTemporaryException(final Throwable ex) {
+        return Stream.of(ExceptionUtils.getThrowables(ex)).
+                filter(i -> i instanceof TemporaryException).findFirst();
     }
 
     /**
@@ -81,7 +85,7 @@
         final ChannelHandlerContext nettyContext = context.getChannelHandlerContext();
         final RequestMessage msg = context.getRequestMessage();
         final Settings settings = context.getSettings();
-        final MessageSerializer serializer = nettyContext.channel().attr(StateKey.SERIALIZER).get();
+        final MessageSerializer<?> serializer = nettyContext.channel().attr(StateKey.SERIALIZER).get();
         final boolean useBinary = nettyContext.channel().attr(StateKey.USE_BINARY).get();
         boolean warnOnce = false;
 
@@ -251,24 +255,11 @@
      *
      * @param itty a reference to the current {@link Iterator} of results - it is not meant to be forwarded in
      *             this method
-     * @deprecated As of release 3.4.0, replaced by {@link #generateResultMetaData(ChannelHandlerContext, RequestMessage, ResponseStatusCode, Iterator, Settings)}
-     */
-    @Deprecated
-    protected Map<String, Object> generateMetaData(final ChannelHandlerContext ctx, final RequestMessage msg,
-                                                   final ResponseStatusCode code, final Iterator itty) {
-        return Collections.emptyMap();
-    }
-
-    /**
-     * Generates response result meta-data to put on a {@link ResponseMessage}.
-     *
-     * @param itty a reference to the current {@link Iterator} of results - it is not meant to be forwarded in
-     *             this method
      */
     protected Map<String, Object> generateResultMetaData(final ChannelHandlerContext ctx, final RequestMessage msg,
                                                          final ResponseStatusCode code, final Iterator itty,
                                                          final Settings settings) {
-        return generateMetaData(ctx, msg, code, itty);
+        return Collections.emptyMap();
     }
 
     /**
@@ -289,52 +280,8 @@
         return metaData;
     }
 
-    /**
-     * @deprecated As of release 3.3.8, replaced by {@link #makeFrame(Context, RequestMessage, MessageSerializer, boolean, List, ResponseStatusCode, Map)}.
-     */
-    @Deprecated
-    protected static Frame makeFrame(final ChannelHandlerContext ctx, final RequestMessage msg,
-                                     final MessageSerializer serializer, final boolean useBinary, final List<Object> aggregate,
-                                     final ResponseStatusCode code, final Map<String,Object> responseMetaData,
-                                     final Map<String,Object> statusAttributes) throws Exception {
-        final Context context = new Context(msg, ctx, null, null, null, null); // dummy context, good only for writing response messages to the channel
-        final ResponseHandlerContext rhc = new ResponseHandlerContext(context);
-        return makeFrame(rhc, msg, serializer, useBinary, aggregate, code, responseMetaData, statusAttributes);
-    }
-
-    /**
-     * @deprecated As of release 3.3.8, replaced by {@link #makeFrame(Context, RequestMessage, MessageSerializer, boolean, List, ResponseStatusCode, Map)}.
-     */
-    @Deprecated
-    protected static Frame makeFrame(final ResponseHandlerContext rhc, final RequestMessage msg,
-                                     final MessageSerializer serializer, final boolean useBinary, final List<Object> aggregate,
-                                     final ResponseStatusCode code, final Map<String,Object> responseMetaData) throws Exception {
-        return makeFrame(rhc.getContext(), msg, serializer, useBinary,aggregate, code, responseMetaData);
-    }
-
-    /**
-     * @deprecated As of release 3.3.8, replaced by {@link #makeFrame(Context, RequestMessage, MessageSerializer, boolean, List, ResponseStatusCode, Map)}.
-     */
-    @Deprecated
-    protected static Frame makeFrame(final ResponseHandlerContext rhc, final RequestMessage msg,
-                                     final MessageSerializer serializer, final boolean useBinary, final List<Object> aggregate,
-                                     final ResponseStatusCode code, final Map<String,Object> responseMetaData,
-                                     final Map<String,Object> statusAttributes) throws Exception {
-        return makeFrame(rhc.getContext(), msg, serializer, useBinary,aggregate, code, responseMetaData, statusAttributes);
-    }
-
-    /**
-     * @deprecated As of release 3.4.3, replaced by {@link #makeFrame(Context, RequestMessage, MessageSerializer, boolean, List, ResponseStatusCode, Map)}.
-     */
-    @Deprecated
     protected static Frame makeFrame(final Context ctx, final RequestMessage msg,
-                                     final MessageSerializer serializer, final boolean useBinary, final List<Object> aggregate,
-                                     final ResponseStatusCode code, final Map<String,Object> responseMetaData) throws Exception {
-        return makeFrame(ctx, msg, serializer, useBinary,aggregate, code, responseMetaData, Collections.emptyMap());
-    }
-
-    protected static Frame makeFrame(final Context ctx, final RequestMessage msg,
-                                     final MessageSerializer serializer, final boolean useBinary, final List<Object> aggregate,
+                                     final MessageSerializer<?> serializer, final boolean useBinary, final List<Object> aggregate,
                                      final ResponseStatusCode code, final Map<String,Object> responseMetaData,
                                      final Map<String,Object> statusAttributes) throws Exception {
         try {
@@ -349,7 +296,7 @@
             } else {
                 // the expectation is that the GremlinTextRequestDecoder will have placed a MessageTextSerializer
                 // instance on the channel.
-                final MessageTextSerializer textSerializer = (MessageTextSerializer) serializer;
+                final MessageTextSerializer<?> textSerializer = (MessageTextSerializer<?>) serializer;
                 return new Frame(textSerializer.serializeResponseAsString(ResponseMessage.build(msg)
                         .code(code)
                         .statusAttributes(statusAttributes)
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/OpLoader.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/OpLoader.java
index 5b69a64..b165436 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/OpLoader.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/OpLoader.java
@@ -65,7 +65,7 @@
     }
 
     /**
-     * Gets an {@link OpProcessor} by its name. If it cannot be found an {@link Optional#EMPTY} is returned.
+     * Gets an {@link OpProcessor} by its name. If it cannot be found an {@link Optional#empty()} is returned.
      */
     public static Optional<OpProcessor> getProcessor(final String name) {
         return Optional.ofNullable(processors.get(name));
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/session/Session.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/session/Session.java
index 8d4fe3f..f7934d5 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/session/Session.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/session/Session.java
@@ -93,7 +93,7 @@
     private final ConcurrentHashMap<String, Session> sessions;
 
     public Session(final String session, final Context context, final ConcurrentHashMap<String, Session> sessions) {
-        logger.info("New session established for {}", session);
+        logger.debug("New session established for {}", session);
         this.session = session;
         this.bindings = new SimpleBindings();
         this.settings = context.getSettings();
@@ -201,7 +201,7 @@
                     try {
                         executor.submit(() -> {
                             if (g.tx().isOpen()) {
-                                logger.info("Rolling back open transactions on {} before killing session: {}", gName, session);
+                                logger.debug("Rolling back open transactions on {} before killing session: {}", gName, session);
                                 g.tx().rollback();
                             }
                         }).get(configuredPerGraphCloseTimeout, TimeUnit.MILLISECONDS);
@@ -211,7 +211,7 @@
                 }
             });
         } else {
-            logger.info("Skipped attempt to close open graph transactions on {} - close was forced", session);
+            logger.debug("Skipped attempt to close open graph transactions on {} - close was forced", session);
         }
 
         // prevent any additional requests from processing. if the kill was not "forced" then jobs were scheduled to
@@ -225,7 +225,7 @@
         // once a session is dead release the gauges in the registry for it
         MetricManager.INSTANCE.getRegistry().removeMatching((s, metric) -> s.contains(session));
 
-        logger.info("Session {} closed", session);
+        logger.debug("Session {} closed", session);
     }
 
     private GremlinExecutor.Builder initializeGremlinExecutor() {
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/session/SessionOpProcessor.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/session/SessionOpProcessor.java
index 2bcb430..17fa1a0 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/session/SessionOpProcessor.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/session/SessionOpProcessor.java
@@ -18,34 +18,60 @@
  */
 package org.apache.tinkerpop.gremlin.server.op.session;
 
+import io.netty.channel.ChannelHandlerContext;
+import org.apache.tinkerpop.gremlin.driver.MessageSerializer;
 import org.apache.tinkerpop.gremlin.driver.Tokens;
 import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
 import org.apache.tinkerpop.gremlin.groovy.jsr223.GroovyCompilerGremlinPlugin;
+import org.apache.tinkerpop.gremlin.jsr223.JavaTranslator;
+import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.util.BytecodeHelper;
+import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalInterruptedException;
 import org.apache.tinkerpop.gremlin.server.Context;
+import org.apache.tinkerpop.gremlin.server.GraphManager;
 import org.apache.tinkerpop.gremlin.server.GremlinServer;
 import org.apache.tinkerpop.gremlin.server.OpProcessor;
 import org.apache.tinkerpop.gremlin.server.Settings;
+import org.apache.tinkerpop.gremlin.server.auth.AuthenticatedUser;
+import org.apache.tinkerpop.gremlin.server.handler.Frame;
 import org.apache.tinkerpop.gremlin.server.handler.StateKey;
 import org.apache.tinkerpop.gremlin.server.op.AbstractEvalOpProcessor;
 import org.apache.tinkerpop.gremlin.server.op.OpProcessorException;
 import org.apache.tinkerpop.gremlin.server.util.MetricManager;
+import org.apache.tinkerpop.gremlin.server.util.TraverserIterator;
 import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONVersion;
 import org.apache.tinkerpop.gremlin.util.function.ThrowingConsumer;
+import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import javax.script.Bindings;
+import javax.script.ScriptException;
+import javax.script.SimpleBindings;
+import java.lang.reflect.UndeclaredThrowableException;
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeUnit;
 import java.util.function.Function;
 import java.util.function.Supplier;
 
 import static com.codahale.metrics.MetricRegistry.name;
+import static org.apache.tinkerpop.gremlin.process.traversal.GraphOp.TX_COMMIT;
+import static org.apache.tinkerpop.gremlin.process.traversal.GraphOp.TX_ROLLBACK;
 
 /**
  * Simple {@link OpProcessor} implementation that handles {@code ScriptEngine} script evaluation in the context of
@@ -54,6 +80,10 @@
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
 public class SessionOpProcessor extends AbstractEvalOpProcessor {
+    private static final ObjectMapper mapper = GraphSONMapper.build().version(GraphSONVersion.V2_0).create().createMapper();
+    private static final Logger auditLogger = LoggerFactory.getLogger(GremlinServer.AUDIT_LOGGER_NAME);
+    private static final Bindings EMPTY_BINDINGS = new SimpleBindings();
+
     private static final Logger logger = LoggerFactory.getLogger(SessionOpProcessor.class);
     public static final String OP_PROCESSOR_NAME = "session";
 
@@ -122,13 +152,16 @@
     }
 
     /**
-     * Session based requests accept a "close" operator in addition to "eval". A close will trigger the session to be
-     * killed and any uncommitted transaction to be rolled-back.
+     * Older versions of session-based requests accepted a "close" operator in addition to "eval". This feature
+     * effectively acts as a do-nothing for 3.5.0 to allow older versions of the drivers to connect. At some point
+     * this may be removed completely. Note that closing the channel kills the session now.
      */
     @Override
-    public Optional<ThrowingConsumer<Context>> selectOther(final RequestMessage requestMessage) throws OpProcessorException {
-        // deprecated the "close" message at 3.3.11 - should probably leave this check for the "close" token so that
-        // if older versions of the driver connect they won't get an error. can basically just write back a NO_CONTENT
+    public Optional<ThrowingConsumer<Context>> selectOther(final Context ctx) throws OpProcessorException {
+        final RequestMessage requestMessage = ctx.getRequestMessage();
+
+        // deprecated the "close" message at 3.3.11 - left this check for the "close" token so that if older versions
+        // of the driver connect they won't get an error. basically just writes back a NO_CONTENT
         // for the immediate term in 3.5.0 and then for some future version remove support for the message completely
         // and thus disallow older driver versions from connecting at all.
         if (requestMessage.getOp().equals(Tokens.OPS_CLOSE)) {
@@ -138,24 +171,53 @@
                 throw new OpProcessorException(msg, ResponseMessage.build(requestMessage).code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(msg).create());
             }
 
-            final boolean force = requestMessage.<Boolean>optionalArgs(Tokens.ARGS_FORCE).orElse(false);
-
             return Optional.of(rhc -> {
-                final Session sessionToClose = sessions.get(requestMessage.getArgs().get(Tokens.ARGS_SESSION).toString());
-                if (null != sessionToClose) {
-                    sessionToClose.manualKill(force);
-                }
-
                 // send back a confirmation of the close
                 rhc.writeAndFlush(ResponseMessage.build(requestMessage)
                         .code(ResponseStatusCode.NO_CONTENT)
                         .create());
             });
+        } else if (requestMessage.getOp().equals(Tokens.OPS_BYTECODE)) {
+            validateTraversalSourceAlias(ctx, requestMessage, validateTraversalRequest(requestMessage));
+            return Optional.of(this::iterateBytecodeTraversal);
         } else {
             return Optional.empty();
         }
     }
 
+    private static void validateTraversalSourceAlias(final Context ctx, final RequestMessage message, final Map<String, String> aliases) throws OpProcessorException {
+        final String traversalSourceBindingForAlias = aliases.values().iterator().next();
+        if (!ctx.getGraphManager().getTraversalSourceNames().contains(traversalSourceBindingForAlias)) {
+            final String msg = String.format("The traversal source [%s] for alias [%s] is not configured on the server.", traversalSourceBindingForAlias, Tokens.VAL_TRAVERSAL_SOURCE_ALIAS);
+            throw new OpProcessorException(msg, ResponseMessage.build(message).code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(msg).create());
+        }
+    }
+
+    private static Map<String, String> validateTraversalRequest(final RequestMessage message) throws OpProcessorException {
+        if (!message.optionalArgs(Tokens.ARGS_GREMLIN).isPresent()) {
+            final String msg = String.format("A message with [%s] op code requires a [%s] argument.", Tokens.OPS_BYTECODE, Tokens.ARGS_GREMLIN);
+            throw new OpProcessorException(msg, ResponseMessage.build(message).code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(msg).create());
+        }
+
+        return validatedAliases(message).get();
+    }
+
+    private static Optional<Map<String, String>> validatedAliases(final RequestMessage message) throws OpProcessorException {
+        final Optional<Map<String, String>> aliases = message.optionalArgs(Tokens.ARGS_ALIASES);
+        if (!aliases.isPresent()) {
+            final String msg = String.format("A message with [%s] op code requires a [%s] argument.", Tokens.OPS_BYTECODE, Tokens.ARGS_ALIASES);
+            throw new OpProcessorException(msg, ResponseMessage.build(message).code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(msg).create());
+        }
+
+        if (aliases.get().size() != 1 || !aliases.get().containsKey(Tokens.VAL_TRAVERSAL_SOURCE_ALIAS)) {
+            final String msg = String.format("A message with [%s] op code requires the [%s] argument to be a Map containing one alias assignment named '%s'.",
+                    Tokens.OPS_BYTECODE, Tokens.ARGS_ALIASES, Tokens.VAL_TRAVERSAL_SOURCE_ALIAS);
+            throw new OpProcessorException(msg, ResponseMessage.build(message).code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(msg).create());
+        }
+
+        return aliases;
+    }
+
     @Override
     public ThrowingConsumer<Context> getEvalOp() {
         return this::evalOp;
@@ -191,6 +253,15 @@
             throw new OpProcessorException(sessionClosedMessage, response);
         }
 
+        // check if the session is bound to this channel, thus one client per session
+        if (!session.isBoundTo(context.getChannelHandlerContext().channel())) {
+            final String sessionClosedMessage = String.format("Session %s is not bound to the connecting client",
+                    session.getSessionId());
+            final ResponseMessage response = ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR)
+                    .statusMessage(sessionClosedMessage).create();
+            throw new OpProcessorException(sessionClosedMessage, response);
+        }
+
         // place the session on the channel context so that it can be used during serialization.  in this way
         // the serialization can occur on the same thread used to execute the gremlin within the session.  this
         // is important given the threadlocal nature of Graph implementation transactions.
@@ -265,4 +336,353 @@
             return bindings;
         };
     }
+
+    private void iterateBytecodeTraversal(final Context context) throws Exception {
+        final RequestMessage msg = context.getRequestMessage();
+        final Settings settings = context.getSettings();
+        logger.debug("Traversal request {} for in thread {}", msg.getRequestId(), Thread.currentThread().getName());
+
+        // right now the TraversalOpProcessor can take a direct GraphSON representation of Bytecode or directly take
+        // deserialized Bytecode object.
+        final Object bytecodeObj = msg.getArgs().get(Tokens.ARGS_GREMLIN);
+        final Bytecode bytecode = bytecodeObj instanceof Bytecode ? (Bytecode) bytecodeObj :
+                mapper.readValue(bytecodeObj.toString(), Bytecode.class);
+
+        // earlier validation in selection of this op method should free us to cast this without worry
+        final Map<String, String> aliases = (Map<String, String>) msg.optionalArgs(Tokens.ARGS_ALIASES).get();
+
+        // timeout override - handle both deprecated and newly named configuration. earlier logic should prevent
+        // both configurations from being submitted at the same time
+        final Map<String, Object> args = msg.getArgs();
+        final long seto = args.containsKey(Tokens.ARGS_EVAL_TIMEOUT) ?
+                ((Number) args.get(Tokens.ARGS_EVAL_TIMEOUT)).longValue() : context.getSettings().getEvaluationTimeout();
+
+        final GraphManager graphManager = context.getGraphManager();
+        final String traversalSourceName = aliases.entrySet().iterator().next().getValue();
+        final TraversalSource g = graphManager.getTraversalSource(traversalSourceName);
+
+        // todo: should session be grabbed here???
+        final Session session = getSession(context, msg);
+
+        // handle bytecode based graph operations like commit/rollback commands
+        if (BytecodeHelper.isGraphOperation(bytecode)) {
+            handleGraphOperation(bytecode, g.getGraph(), context);
+            return;
+        }
+
+        final Traversal.Admin<?, ?> traversal;
+        try {
+            final Optional<String> lambdaLanguage = BytecodeHelper.getLambdaLanguage(bytecode);
+            if (!lambdaLanguage.isPresent())
+                traversal = JavaTranslator.of(g).translate(bytecode);
+            else
+                traversal = session.getGremlinExecutor().eval(bytecode, EMPTY_BINDINGS, lambdaLanguage.get(), traversalSourceName);
+        } catch (ScriptException ex) {
+            logger.error("Traversal contains a lambda that cannot be compiled", ex);
+            throw new OpProcessorException("Traversal contains a lambda that cannot be compiled",
+                    ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR_EVALUATION)
+                            .statusMessage(ex.getMessage())
+                            .statusAttributeException(ex).create());
+        } catch (Exception ex) {
+            logger.error("Could not deserialize the Traversal instance", ex);
+            throw new OpProcessorException("Could not deserialize the Traversal instance",
+                    ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR_SERIALIZATION)
+                            .statusMessage(ex.getMessage())
+                            .statusAttributeException(ex).create());
+        }
+
+        if (settings.enableAuditLog) {
+            AuthenticatedUser user = context.getChannelHandlerContext().channel().attr(StateKey.AUTHENTICATED_USER).get();
+            if (null == user) {    // This is expected when using the AllowAllAuthenticator
+                user = AuthenticatedUser.ANONYMOUS_USER;
+            }
+            String address = context.getChannelHandlerContext().channel().remoteAddress().toString();
+            if (address.startsWith("/") && address.length() > 1) address = address.substring(1);
+            auditLogger.info("User {} with address {} requested: {}", user.getName(), address, bytecode);
+        }
+        if (settings.authentication.enableAuditLog) {
+            String address = context.getChannelHandlerContext().channel().remoteAddress().toString();
+            if (address.startsWith("/") && address.length() > 1) address = address.substring(1);
+            auditLogger.info("User with address {} requested: {}", address, bytecode);
+        }
+
+        // todo: timer matter???
+        // final Timer.Context timerContext = traversalOpTimer.time();
+
+        final FutureTask<Void> evalFuture = new FutureTask<>(() -> {
+            final Graph graph = g.getGraph();
+
+            try {
+                beforeProcessing(graph, context);
+
+                try {
+                    // compile the traversal - without it getEndStep() has nothing in it
+                    traversal.applyStrategies();
+                    handleIterator(context, new TraverserIterator(traversal), graph);
+                } catch (Exception ex) {
+                    Throwable t = ex;
+                    if (ex instanceof UndeclaredThrowableException)
+                        t = t.getCause();
+
+                    // if any exception in the chain is TemporaryException then we should respond with the right error
+                    // code so that the client knows to retry
+                    final Optional<Throwable> possibleTemporaryException = determineIfTemporaryException(ex);
+                    if (possibleTemporaryException.isPresent()) {
+                        context.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR_TEMPORARY)
+                                .statusMessage(possibleTemporaryException.get().getMessage())
+                                .statusAttributeException(possibleTemporaryException.get()).create());
+                    } else if (t instanceof InterruptedException || t instanceof TraversalInterruptedException) {
+                        final String errorMessage = String.format("A timeout occurred during traversal evaluation of [%s] - consider increasing the limit given to evaluationTimeout", msg);
+                        logger.warn(errorMessage);
+                        context.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR_TIMEOUT)
+                                .statusMessage(errorMessage)
+                                .statusAttributeException(ex).create());
+                    } else {
+                        logger.warn(String.format("Exception processing a Traversal on iteration for request [%s].", msg.getRequestId()), ex);
+                        context.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR)
+                                .statusMessage(ex.getMessage())
+                                .statusAttributeException(ex).create());
+                    }
+                    onError(graph, context);
+                }
+            } catch (Exception ex) {
+                final Optional<Throwable> possibleTemporaryException = determineIfTemporaryException(ex);
+                if (possibleTemporaryException.isPresent()) {
+                    context.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR_TEMPORARY)
+                            .statusMessage(possibleTemporaryException.get().getMessage())
+                            .statusAttributeException(possibleTemporaryException.get()).create());
+                } else {
+                    logger.warn(String.format("Exception processing a Traversal on request [%s].", msg.getRequestId()), ex);
+                    context.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR)
+                            .statusMessage(ex.getMessage())
+                            .statusAttributeException(ex).create());
+                }
+                onError(graph, context);
+            } finally {
+                // todo: timer matter???
+                //timerContext.stop();
+            }
+
+            return null;
+        });
+
+        submitToGremlinExecutor(context, seto, session, evalFuture);
+    }
+
+    private static void submitToGremlinExecutor(final Context context, final long seto, final Session session,
+                                                final FutureTask<Void> evalFuture) {
+        final Future<?> executionFuture = session.getGremlinExecutor().getExecutorService().submit(evalFuture);
+        if (seto > 0) {
+            // Schedule a timeout in the thread pool for future execution
+            context.getScheduledExecutorService().schedule(() -> executionFuture.cancel(true), seto, TimeUnit.MILLISECONDS);
+        }
+    }
+
+    /**
+     * If {@link Bytecode} is detected to contain a "graph operation" then it gets processed by this method.
+     */
+    protected void handleGraphOperation(final Bytecode bytecode, final Graph graph, final Context context) {
+        final RequestMessage msg = context.getRequestMessage();
+        final Session session = getSession(context, msg);
+        if (graph.features().graph().supportsTransactions()) {
+            if (TX_COMMIT.equals(bytecode) || TX_ROLLBACK.equals(bytecode)) {
+                final boolean commit = TX_COMMIT.equals(bytecode);
+                submitToGremlinExecutor(context, 0, session, new FutureTask<>(() -> {
+                    try {
+                        if (graph.tx().isOpen()) {
+                            if (commit)
+                                graph.tx().commit();
+                            else
+                                graph.tx().rollback();
+                        }
+
+                        // write back a no-op for success
+                        final Map<String, Object> attributes = generateStatusAttributes(
+                                context.getChannelHandlerContext(), msg,
+                                ResponseStatusCode.NO_CONTENT, Collections.emptyIterator(), context.getSettings());
+                        context.writeAndFlush(ResponseMessage.build(msg)
+                                .code(ResponseStatusCode.NO_CONTENT)
+                                .statusAttributes(attributes)
+                                .create());
+
+                    } catch (Exception ex) {
+                        final Optional<Throwable> possibleTemporaryException = determineIfTemporaryException(ex);
+                        if (possibleTemporaryException.isPresent()) {
+                            context.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR_TEMPORARY)
+                                    .statusMessage(possibleTemporaryException.get().getMessage())
+                                    .statusAttributeException(possibleTemporaryException.get()).create());
+                        } else {
+                            logger.warn(String.format("Exception processing a Traversal on request [%s].", msg.getRequestId()), ex);
+                            context.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR)
+                                    .statusMessage(ex.getMessage())
+                                    .statusAttributeException(ex).create());
+                        }
+                        onError(graph, context);
+                    }
+
+                    return null;
+                }));
+            } else {
+                throw new IllegalStateException(String.format(
+                        "Bytecode in request is not a recognized graph operation: %s", bytecode.toString()));
+            }
+        }
+    }
+
+    protected void beforeProcessing(final Graph graph, final Context ctx) {
+        final boolean managedTransactionsForRequest = manageTransactions ?
+                true : (Boolean) ctx.getRequestMessage().getArgs().getOrDefault(Tokens.ARGS_MANAGE_TRANSACTION, false);
+        if (managedTransactionsForRequest && graph.features().graph().supportsTransactions() && graph.tx().isOpen()) graph.tx().rollback();
+    }
+
+    protected void onError(final Graph graph, final Context ctx) {
+        final boolean managedTransactionsForRequest = manageTransactions ?
+                true : (Boolean) ctx.getRequestMessage().getArgs().getOrDefault(Tokens.ARGS_MANAGE_TRANSACTION, false);
+        if (managedTransactionsForRequest && graph.features().graph().supportsTransactions() && graph.tx().isOpen()) graph.tx().rollback();
+    }
+
+    protected void onTraversalSuccess(final Graph graph, final Context ctx) {
+        final boolean managedTransactionsForRequest = manageTransactions ?
+                true : (Boolean) ctx.getRequestMessage().getArgs().getOrDefault(Tokens.ARGS_MANAGE_TRANSACTION, false);
+        if (managedTransactionsForRequest && graph.features().graph().supportsTransactions() && graph.tx().isOpen()) graph.tx().commit();
+    }
+
+    protected void handleIterator(final Context context, final Iterator itty, final Graph graph) throws InterruptedException {
+        final ChannelHandlerContext nettyContext = context.getChannelHandlerContext();
+        final RequestMessage msg = context.getRequestMessage();
+        final Settings settings = context.getSettings();
+        final MessageSerializer serializer = nettyContext.channel().attr(StateKey.SERIALIZER).get();
+        final boolean useBinary = nettyContext.channel().attr(StateKey.USE_BINARY).get();
+        boolean warnOnce = false;
+
+        // we have an empty iterator - happens on stuff like: g.V().iterate()
+        if (!itty.hasNext()) {
+            final Map<String, Object> attributes = generateStatusAttributes(nettyContext, msg, ResponseStatusCode.NO_CONTENT, itty, settings);
+
+            // as there is nothing left to iterate if we are transaction managed then we should execute a
+            // commit here before we send back a NO_CONTENT which implies success
+            onTraversalSuccess(graph, context);
+            context.writeAndFlush(ResponseMessage.build(msg)
+                    .code(ResponseStatusCode.NO_CONTENT)
+                    .statusAttributes(attributes)
+                    .create());
+            return;
+        }
+
+        // the batch size can be overridden by the request
+        final int resultIterationBatchSize = (Integer) msg.optionalArgs(Tokens.ARGS_BATCH_SIZE)
+                .orElse(settings.resultIterationBatchSize);
+        List<Object> aggregate = new ArrayList<>(resultIterationBatchSize);
+
+        // use an external control to manage the loop as opposed to just checking hasNext() in the while.  this
+        // prevent situations where auto transactions create a new transaction after calls to commit() withing
+        // the loop on calls to hasNext().
+        boolean hasMore = itty.hasNext();
+
+        while (hasMore) {
+            if (Thread.interrupted()) throw new InterruptedException();
+
+            // check if an implementation needs to force flush the aggregated results before the iteration batch
+            // size is reached.
+            final boolean forceFlush = isForceFlushed(nettyContext, msg, itty);
+
+            // have to check the aggregate size because it is possible that the channel is not writeable (below)
+            // so iterating next() if the message is not written and flushed would bump the aggregate size beyond
+            // the expected resultIterationBatchSize.  Total serialization time for the response remains in
+            // effect so if the client is "slow" it may simply timeout.
+            //
+            // there is a need to check hasNext() on the iterator because if the channel is not writeable the
+            // previous pass through the while loop will have next()'d the iterator and if it is "done" then a
+            // NoSuchElementException will raise its head. also need a check to ensure that this iteration doesn't
+            // require a forced flush which can be forced by sub-classes.
+            //
+            // this could be placed inside the isWriteable() portion of the if-then below but it seems better to
+            // allow iteration to continue into a batch if that is possible rather than just doing nothing at all
+            // while waiting for the client to catch up
+            if (aggregate.size() < resultIterationBatchSize && itty.hasNext() && !forceFlush) aggregate.add(itty.next());
+
+            // Don't keep executor busy if client has already given up; there is no way to catch up if the channel is
+            // not active, and hence we should break the loop.
+            if (!nettyContext.channel().isActive()) {
+                onError(graph, context);
+                break;
+            }
+
+            // send back a page of results if batch size is met or if it's the end of the results being iterated.
+            // also check writeability of the channel to prevent OOME for slow clients.
+            //
+            // clients might decide to close the Netty channel to the server with a CloseWebsocketFrame after errors
+            // like CorruptedFrameException. On the server, although the channel gets closed, there might be some
+            // executor threads waiting for watermark to clear which will not clear in these cases since client has
+            // already given up on these requests. This leads to these executors waiting for the client to consume
+            // results till the timeout. checking for isActive() should help prevent that.
+            if (nettyContext.channel().isActive() && nettyContext.channel().isWritable()) {
+                if (forceFlush || aggregate.size() == resultIterationBatchSize || !itty.hasNext()) {
+                    final ResponseStatusCode code = itty.hasNext() ? ResponseStatusCode.PARTIAL_CONTENT : ResponseStatusCode.SUCCESS;
+
+                    // serialize here because in sessionless requests the serialization must occur in the same
+                    // thread as the eval.  as eval occurs in the GremlinExecutor there's no way to get back to the
+                    // thread that processed the eval of the script so, we have to push serialization down into that
+                    final Map<String, Object> metadata = generateResultMetaData(nettyContext, msg, code, itty, settings);
+                    final Map<String, Object> statusAttrb = generateStatusAttributes(nettyContext, msg, code, itty, settings);
+                    Frame frame = null;
+                    try {
+                        frame = makeFrame(context, msg, serializer, useBinary, aggregate, code,
+                                metadata, statusAttrb);
+                    } catch (Exception ex) {
+                        // a frame may use a Bytebuf which is a countable release - if it does not get written
+                        // downstream it needs to be released here
+                        if (frame != null) frame.tryRelease();
+
+                        // exception is handled in makeFrame() - serialization error gets written back to driver
+                        // at that point
+                        onError(graph, context);
+                        break;
+                    }
+
+                    try {
+                        // only need to reset the aggregation list if there's more stuff to write
+                        if (itty.hasNext())
+                            aggregate = new ArrayList<>(resultIterationBatchSize);
+                        else {
+                            // iteration and serialization are both complete which means this finished successfully. note that
+                            // errors internal to script eval or timeout will rollback given GremlinServer's global configurations.
+                            // local errors will get rolledback below because the exceptions aren't thrown in those cases to be
+                            // caught by the GremlinExecutor for global rollback logic. this only needs to be committed if
+                            // there are no more items to iterate and serialization is complete
+                            onTraversalSuccess(graph, context);
+
+                            // exit the result iteration loop as there are no more results left.  using this external control
+                            // because of the above commit.  some graphs may open a new transaction on the call to
+                            // hasNext()
+                            hasMore = false;
+                        }
+                    } catch (Exception ex) {
+                        // a frame may use a Bytebuf which is a countable release - if it does not get written
+                        // downstream it needs to be released here
+                        if (frame != null) frame.tryRelease();
+                        throw ex;
+                    }
+
+                    if (!itty.hasNext()) iterateComplete(nettyContext, msg, itty);
+
+                    // the flush is called after the commit has potentially occurred.  in this way, if a commit was
+                    // required then it will be 100% complete before the client receives it. the "frame" at this point
+                    // should have completely detached objects from the transaction (i.e. serialization has occurred)
+                    // so a new one should not be opened on the flush down the netty pipeline
+                    context.writeAndFlush(code, frame);
+                }
+            } else {
+                // don't keep triggering this warning over and over again for the same request
+                if (!warnOnce) {
+                    logger.warn("Pausing response writing as writeBufferHighWaterMark exceeded on {} - writing will continue once client has caught up", msg);
+                    warnOnce = true;
+                }
+
+                // since the client is lagging we can hold here for a period of time for the client to catch up.
+                // this isn't blocking the IO thread - just a worker.
+                TimeUnit.MILLISECONDS.sleep(10);
+            }
+        }
+    }
 }
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/standard/StandardOpProcessor.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/standard/StandardOpProcessor.java
index 746397a..81df30c 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/standard/StandardOpProcessor.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/standard/StandardOpProcessor.java
@@ -84,7 +84,7 @@
     }
 
     @Override
-    public Optional<ThrowingConsumer<Context>> selectOther(final RequestMessage requestMessage)  throws OpProcessorException {
+    public Optional<ThrowingConsumer<Context>> selectOther(final Context ctx)  throws OpProcessorException {
         return Optional.empty();
     }
 
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/traversal/TraversalOpProcessor.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/traversal/TraversalOpProcessor.java
index 07ca83b..3e4788f 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/traversal/TraversalOpProcessor.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/traversal/TraversalOpProcessor.java
@@ -19,8 +19,6 @@
 package org.apache.tinkerpop.gremlin.server.op.traversal;
 
 import com.codahale.metrics.Timer;
-import com.github.benmanes.caffeine.cache.Cache;
-import com.github.benmanes.caffeine.cache.Caffeine;
 import io.netty.channel.ChannelHandlerContext;
 import org.apache.tinkerpop.gremlin.driver.MessageSerializer;
 import org.apache.tinkerpop.gremlin.driver.Tokens;
@@ -30,7 +28,6 @@
 import org.apache.tinkerpop.gremlin.jsr223.JavaTranslator;
 import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
-import org.apache.tinkerpop.gremlin.process.traversal.TraversalSideEffects;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
 import org.apache.tinkerpop.gremlin.process.traversal.util.BytecodeHelper;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalInterruptedException;
@@ -39,12 +36,12 @@
 import org.apache.tinkerpop.gremlin.server.GremlinServer;
 import org.apache.tinkerpop.gremlin.server.OpProcessor;
 import org.apache.tinkerpop.gremlin.server.Settings;
+import org.apache.tinkerpop.gremlin.server.auth.AuthenticatedUser;
 import org.apache.tinkerpop.gremlin.server.handler.Frame;
 import org.apache.tinkerpop.gremlin.server.handler.StateKey;
 import org.apache.tinkerpop.gremlin.server.op.AbstractOpProcessor;
 import org.apache.tinkerpop.gremlin.server.op.OpProcessorException;
 import org.apache.tinkerpop.gremlin.server.util.MetricManager;
-import org.apache.tinkerpop.gremlin.server.util.SideEffectIterator;
 import org.apache.tinkerpop.gremlin.server.util.TraverserIterator;
 import org.apache.tinkerpop.gremlin.structure.Graph;
 import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper;
@@ -59,15 +56,13 @@
 import javax.script.SimpleBindings;
 import java.lang.reflect.UndeclaredThrowableException;
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
-import java.util.UUID;
 import java.util.concurrent.Future;
 import java.util.concurrent.FutureTask;
+import java.util.concurrent.RejectedExecutionException;
 import java.util.concurrent.TimeUnit;
 
 import static com.codahale.metrics.MetricRegistry.name;
@@ -79,62 +74,11 @@
  */
 public class TraversalOpProcessor extends AbstractOpProcessor {
     private static final Logger logger = LoggerFactory.getLogger(TraversalOpProcessor.class);
+    private static final Logger auditLogger = LoggerFactory.getLogger(GremlinServer.AUDIT_LOGGER_NAME);
     private static final ObjectMapper mapper = GraphSONMapper.build().version(GraphSONVersion.V2_0).create().createMapper();
     public static final String OP_PROCESSOR_NAME = "traversal";
     public static final Timer traversalOpTimer = MetricManager.INSTANCE.getTimer(name(GremlinServer.class, "op", "traversal"));
 
-    public static final Settings.ProcessorSettings DEFAULT_SETTINGS = new Settings.ProcessorSettings();
-
-    /**
-     * Configuration setting for how long a cached side-effect will be available before it is evicted from the cache.
-     *
-     * @deprecated As of release 3.3.8, not directly replaced in the protocol as side-effect retrieval after
-     * traversal iteration is not being promoted anymore as a feature.
-     */
-    @Deprecated
-    public static final String CONFIG_CACHE_EXPIRATION_TIME = "cacheExpirationTime";
-
-    /**
-     * Default timeout for a cached side-effect is ten minutes.
-     *
-     * @deprecated As of release 3.3.8, not directly replaced in the protocol as side-effect retrieval after
-     * traversal iteration is not being promoted anymore as a feature.
-     */
-    @Deprecated
-    public static final long DEFAULT_CACHE_EXPIRATION_TIME = 600000;
-
-    /**
-     * Configuration setting for the maximum number of entries the cache will have.
-     *
-     * @deprecated As of release 3.3.8, not directly replaced in the protocol as side-effect retrieval after
-     * traversal iteration is not being promoted anymore as a feature.
-     */
-    @Deprecated
-    public static final String CONFIG_CACHE_MAX_SIZE = "cacheMaxSize";
-
-    /**
-     * Default size of the max size of the cache.
-     *
-     * @deprecated As of release 3.3.8, not directly replaced in the protocol as side-effect retrieval after
-     * traversal iteration is not being promoted anymore as a feature.
-     */
-    @Deprecated
-    public static final long DEFAULT_CACHE_MAX_SIZE = 1000;
-
-    static {
-        DEFAULT_SETTINGS.className = TraversalOpProcessor.class.getCanonicalName();
-        DEFAULT_SETTINGS.config = new HashMap<String, Object>() {{
-            put(CONFIG_CACHE_EXPIRATION_TIME, DEFAULT_CACHE_EXPIRATION_TIME);
-            put(CONFIG_CACHE_MAX_SIZE, DEFAULT_CACHE_MAX_SIZE);
-        }};
-    }
-
-    /**
-     * @deprecated As of release 3.3.8, not directly replaced in the protocol as side-effect retrieval after
-     * traversal iteration is not being promoted anymore as a feature.
-     */
-    protected static Cache<UUID, TraversalSideEffects> cache = null;
-
     private static final Bindings EMPTY_BINDINGS = new SimpleBindings();
 
     public TraversalOpProcessor() {
@@ -152,23 +96,6 @@
     }
 
     @Override
-    public void init(final Settings settings) {
-        final Settings.ProcessorSettings processorSettings = settings.processors.stream()
-                .filter(p -> p.className.equals(TraversalOpProcessor.class.getCanonicalName()))
-                .findAny().orElse(TraversalOpProcessor.DEFAULT_SETTINGS);
-        final long maxSize = Long.parseLong(processorSettings.config.get(TraversalOpProcessor.CONFIG_CACHE_MAX_SIZE).toString());
-        final long expirationTime = Long.parseLong(processorSettings.config.get(TraversalOpProcessor.CONFIG_CACHE_EXPIRATION_TIME).toString());
-
-        cache = Caffeine.newBuilder()
-                .expireAfterWrite(expirationTime, TimeUnit.MILLISECONDS)
-                .maximumSize(maxSize)
-                .build();
-
-        logger.info("Initialized cache for {} with size {} and expiration time of {} ms",
-                TraversalOpProcessor.class.getSimpleName(), maxSize, expirationTime);
-    }
-
-    @Override
     public ThrowingConsumer<Context> select(final Context context) throws OpProcessorException {
         final RequestMessage message = context.getRequestMessage();
         logger.debug("Selecting processor for RequestMessage {}", message);
@@ -179,62 +106,6 @@
                 validateTraversalSourceAlias(context, message, validateTraversalRequest(message));
                 op = this::iterateBytecodeTraversal;
                 break;
-            case Tokens.OPS_GATHER:
-                final Optional<String> sideEffectForGather = message.optionalArgs(Tokens.ARGS_SIDE_EFFECT);
-                if (!sideEffectForGather.isPresent()) {
-                    final String msg = String.format("A message with an [%s] op code requires a [%s] argument.", Tokens.OPS_GATHER, Tokens.ARGS_SIDE_EFFECT);
-                    throw new OpProcessorException(msg, ResponseMessage.build(message).code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(msg).create());
-                }
-
-                final Optional<String> sideEffectKey = message.optionalArgs(Tokens.ARGS_SIDE_EFFECT_KEY);
-                if (!sideEffectKey.isPresent()) {
-                    final String msg = String.format("A message with an [%s] op code requires a [%s] argument.", Tokens.OPS_GATHER, Tokens.ARGS_SIDE_EFFECT_KEY);
-                    throw new OpProcessorException(msg, ResponseMessage.build(message).code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(msg).create());
-                }
-
-                validateTraversalSourceAlias(context, message, validatedAliases(message).get());
-
-                op = this::gatherSideEffect;
-
-                break;
-            case Tokens.OPS_KEYS:
-                final Optional<String> sideEffectForKeys = message.optionalArgs(Tokens.ARGS_SIDE_EFFECT);
-                if (!sideEffectForKeys.isPresent()) {
-                    final String msg = String.format("A message with an [%s] op code requires a [%s] argument.", Tokens.OPS_GATHER, Tokens.ARGS_SIDE_EFFECT);
-                    throw new OpProcessorException(msg, ResponseMessage.build(message).code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(msg).create());
-                }
-
-                op = varRhc -> {
-                    final RequestMessage msg = context.getRequestMessage();
-                    final Optional<UUID> sideEffect = msg.optionalArgs(Tokens.ARGS_SIDE_EFFECT);
-                    final TraversalSideEffects sideEffects = cache.getIfPresent(sideEffect.get());
-
-                    if (null == sideEffects)
-                        logger.warn("Request for side-effect keys on {} returned no side-effects in the cache", sideEffect.get());
-
-                    handleIterator(varRhc, null == sideEffects ? Collections.emptyIterator() : sideEffects.keys().iterator());
-                };
-
-                break;
-            case Tokens.OPS_CLOSE:
-                final Optional<String> sideEffectForClose = message.optionalArgs(Tokens.ARGS_SIDE_EFFECT);
-                if (!sideEffectForClose.isPresent()) {
-                    final String msg = String.format("A message with an [%s] op code requires a [%s] argument.", Tokens.OPS_CLOSE, Tokens.ARGS_SIDE_EFFECT);
-                    throw new OpProcessorException(msg, ResponseMessage.build(message).code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(msg).create());
-                }
-
-                op = varRhc -> {
-                    final RequestMessage msg = context.getRequestMessage();
-                    logger.debug("Close request {} for in thread {}", msg.getRequestId(), Thread.currentThread().getName());
-
-                    final Optional<UUID> sideEffect = msg.optionalArgs(Tokens.ARGS_SIDE_EFFECT);
-                    cache.invalidate(sideEffect.get());
-
-                    final String successMessage = String.format("Successfully cleared side effect cache for [%s].", Tokens.ARGS_SIDE_EFFECT);
-                    varRhc.writeAndFlush(ResponseMessage.build(message).code(ResponseStatusCode.NO_CONTENT).statusMessage(successMessage).create());
-                };
-
-                break;
             case Tokens.OPS_INVALID:
                 final String msgInvalid = String.format("Message could not be parsed.  Check the format of the request. [%s]", message);
                 throw new OpProcessorException(msgInvalid, ResponseMessage.build(message).code(ResponseStatusCode.REQUEST_ERROR_MALFORMED_REQUEST).statusMessage(msgInvalid).create());
@@ -279,80 +150,9 @@
         return aliases;
     }
 
-    private void gatherSideEffect(final Context context) throws OpProcessorException {
-        final RequestMessage msg = context.getRequestMessage();
-        logger.debug("Side-effect request {} for in thread {}", msg.getRequestId(), Thread.currentThread().getName());
-
-        // earlier validation in selection of this op method should free us to cast this without worry
-        final Optional<UUID> sideEffect = msg.optionalArgs(Tokens.ARGS_SIDE_EFFECT);
-        final Optional<String> sideEffectKey = msg.optionalArgs(Tokens.ARGS_SIDE_EFFECT_KEY);
-        final Map<String, String> aliases = (Map<String, String>) msg.optionalArgs(Tokens.ARGS_ALIASES).get();
-
-        final GraphManager graphManager = context.getGraphManager();
-        final String traversalSourceName = aliases.entrySet().iterator().next().getValue();
-        final TraversalSource g = graphManager.getTraversalSource(traversalSourceName);
-
-        final Timer.Context timerContext = traversalOpTimer.time();
-        try {
-            final ChannelHandlerContext ctx = context.getChannelHandlerContext();
-            final Graph graph = g.getGraph();
-
-            context.getGremlinExecutor().getExecutorService().submit(() -> {
-                try {
-                    beforeProcessing(graph, context);
-
-                    try {
-                        final TraversalSideEffects sideEffects = cache.getIfPresent(sideEffect.get());
-
-                        if (null == sideEffects) {
-                            final String errorMessage = String.format("Could not find side-effects for %s.", sideEffect.get());
-                            logger.warn(errorMessage);
-                            context.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR).statusMessage(errorMessage).create());
-                            onError(graph, context);
-                            return;
-                        }
-
-                        if (!sideEffects.exists(sideEffectKey.get())) {
-                            final String errorMessage = String.format("Could not find side-effect key for %s in %s.", sideEffectKey.get(), sideEffect.get());
-                            logger.warn(errorMessage);
-                            context.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR).statusMessage(errorMessage).create());
-                            onError(graph, context);
-                            return;
-                        }
-
-                        handleIterator(context, new SideEffectIterator(sideEffects.get(sideEffectKey.get()), sideEffectKey.get()));
-                    } catch (Exception ex) {
-                        logger.warn(String.format("Exception processing a side-effect on iteration for request [%s].", msg.getRequestId()), ex);
-                        context.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR)
-                                                             .statusMessage(ex.getMessage())
-                                                             .statusAttributeException(ex).create());
-                        onError(graph, context);
-                        return;
-                    }
-
-                    onSideEffectSuccess(graph, context);
-                } catch (Exception ex) {
-                    logger.warn(String.format("Exception processing a side-effect on request [%s].", msg.getRequestId()), ex);
-                    context.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR)
-                                                         .statusMessage(ex.getMessage())
-                                                         .statusAttributeException(ex).create());
-                    onError(graph, context);
-                } finally {
-                    timerContext.stop();
-                }
-            });
-
-        } catch (Exception ex) {
-            timerContext.stop();
-            throw new OpProcessorException("Could not iterate the side-effect instance",
-                    ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR)
-                            .statusMessage(ex.getMessage())
-                            .statusAttributeException(ex).create());
-        }
-    }
-
     private void iterateBytecodeTraversal(final Context context) throws Exception {
         final RequestMessage msg = context.getRequestMessage();
+        final Settings settings = context.getSettings();
         logger.debug("Traversal request {} for in thread {}", msg.getRequestId(), Thread.currentThread().getName());
 
         // right now the TraversalOpProcessor can take a direct GraphSON representation of Bytecode or directly take
@@ -367,11 +167,8 @@
         // timeout override - handle both deprecated and newly named configuration. earlier logic should prevent
         // both configurations from being submitted at the same time
         final Map<String, Object> args = msg.getArgs();
-        final long seto = args.containsKey(Tokens.ARGS_SCRIPT_EVAL_TIMEOUT) || args.containsKey(Tokens.ARGS_EVAL_TIMEOUT)
-                // could be sent as an integer or long
-                ? (args.containsKey(Tokens.ARGS_SCRIPT_EVAL_TIMEOUT) ?
-                ((Number) args.get(Tokens.ARGS_SCRIPT_EVAL_TIMEOUT)).longValue() : ((Number) args.get(Tokens.ARGS_EVAL_TIMEOUT)).longValue())
-                : context.getSettings().getEvaluationTimeout();
+        final long seto = args.containsKey(Tokens.ARGS_EVAL_TIMEOUT) ?
+                ((Number) args.get(Tokens.ARGS_EVAL_TIMEOUT)).longValue() : context.getSettings().getEvaluationTimeout();
 
         final GraphManager graphManager = context.getGraphManager();
         final String traversalSourceName = aliases.entrySet().iterator().next().getValue();
@@ -387,7 +184,7 @@
         } catch (ScriptException ex) {
             logger.error("Traversal contains a lambda that cannot be compiled", ex);
             throw new OpProcessorException("Traversal contains a lambda that cannot be compiled",
-                    ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR_SCRIPT_EVALUATION)
+                    ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR_EVALUATION)
                             .statusMessage(ex.getMessage())
                             .statusAttributeException(ex).create());
         } catch (Exception ex) {
@@ -397,6 +194,20 @@
                             .statusMessage(ex.getMessage())
                             .statusAttributeException(ex).create());
         }
+        if (settings.enableAuditLog) {
+            AuthenticatedUser user = context.getChannelHandlerContext().channel().attr(StateKey.AUTHENTICATED_USER).get();
+            if (null == user) {    // This is expected when using the AllowAllAuthenticator
+                user = AuthenticatedUser.ANONYMOUS_USER;
+            }
+            String address = context.getChannelHandlerContext().channel().remoteAddress().toString();
+            if (address.startsWith("/") && address.length() > 1) address = address.substring(1);
+            auditLogger.info("User {} with address {} requested: {}", user.getName(), address, bytecode);
+        }
+        if (settings.authentication.enableAuditLog) {
+            String address = context.getChannelHandlerContext().channel().remoteAddress().toString();
+            if (address.startsWith("/") && address.length() > 1) address = address.substring(1);
+            auditLogger.info("User with address {} requested: {}", address, bytecode);
+        }
 
         final Timer.Context timerContext = traversalOpTimer.time();
         final FutureTask<Void> evalFuture = new FutureTask<>(() -> {
@@ -414,26 +225,39 @@
                     if (ex instanceof UndeclaredThrowableException)
                         t = t.getCause();
 
-                    if (t instanceof InterruptedException || t instanceof TraversalInterruptedException) {
+                    // if any exception in the chain is TemporaryException then we should respond with the right error
+                    // code so that the client knows to retry
+                    final Optional<Throwable> possibleTemporaryException = determineIfTemporaryException(ex);
+                    if (possibleTemporaryException.isPresent()) {
+                        context.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR_TEMPORARY)
+                                .statusMessage(possibleTemporaryException.get().getMessage())
+                                .statusAttributeException(possibleTemporaryException.get()).create());
+                    } else if (t instanceof InterruptedException || t instanceof TraversalInterruptedException) {
                         final String errorMessage = String.format("A timeout occurred during traversal evaluation of [%s] - consider increasing the limit given to evaluationTimeout", msg);
                         logger.warn(errorMessage);
                         context.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR_TIMEOUT)
                                                              .statusMessage(errorMessage)
                                                              .statusAttributeException(ex).create());
-                        onError(graph, context);
                     } else {
                         logger.warn(String.format("Exception processing a Traversal on iteration for request [%s].", msg.getRequestId()), ex);
                         context.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR)
                                                              .statusMessage(ex.getMessage())
                                                              .statusAttributeException(ex).create());
-                        onError(graph, context);
                     }
+                    onError(graph, context);
                 }
             } catch (Exception ex) {
-                logger.warn(String.format("Exception processing a Traversal on request [%s].", msg.getRequestId()), ex);
-                context.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR)
-                                                     .statusMessage(ex.getMessage())
-                                                     .statusAttributeException(ex).create());
+                final Optional<Throwable> possibleTemporaryException = determineIfTemporaryException(ex);
+                if (possibleTemporaryException.isPresent()) {
+                    context.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR_TEMPORARY)
+                            .statusMessage(possibleTemporaryException.get().getMessage())
+                            .statusAttributeException(possibleTemporaryException.get()).create());
+                } else {
+                    logger.warn(String.format("Exception processing a Traversal on request [%s].", msg.getRequestId()), ex);
+                    context.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR)
+                            .statusMessage(ex.getMessage())
+                            .statusAttributeException(ex).create());
+                }
                 onError(graph, context);
             } finally {
                 timerContext.stop();
@@ -442,20 +266,15 @@
             return null;
         });
 
-        final Future<?> executionFuture = context.getGremlinExecutor().getExecutorService().submit(evalFuture);
-        if (seto > 0) {
-            // Schedule a timeout in the thread pool for future execution
-            context.getScheduledExecutorService().schedule(() -> executionFuture.cancel(true), seto, TimeUnit.MILLISECONDS);
-        }
-    }
-
-    @Override
-    protected void iterateComplete(final ChannelHandlerContext ctx, final RequestMessage msg, final Iterator itty) {
-        if (itty instanceof TraverserIterator) {
-            final Traversal.Admin traversal = ((TraverserIterator) itty).getTraversal();
-            if (!traversal.getSideEffects().isEmpty()) {
-                cache.put(msg.getRequestId(), traversal.getSideEffects());
+        try {
+            final Future<?> executionFuture = context.getGremlinExecutor().getExecutorService().submit(evalFuture);
+            if (seto > 0) {
+                // Schedule a timeout in the thread pool for future execution
+                context.getScheduledExecutorService().schedule(() -> executionFuture.cancel(true), seto, TimeUnit.MILLISECONDS);
             }
+        } catch (RejectedExecutionException ree) {
+            context.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.TOO_MANY_REQUESTS)
+                    .statusMessage("Rate limiting").create());
         }
     }
 
@@ -471,51 +290,18 @@
         if (graph.features().graph().supportsTransactions() && graph.tx().isOpen()) graph.tx().commit();
     }
 
-    protected void onSideEffectSuccess(final Graph graph, final Context ctx) {
-        // there was no "writing" here, just side-effect retrieval, so if a transaction was opened then
-        // just close with rollback
-        if (graph.features().graph().supportsTransactions() && graph.tx().isOpen()) graph.tx().rollback();
-    }
-
-    @Override
-    protected Map<String, Object> generateMetaData(final ChannelHandlerContext ctx, final RequestMessage msg,
-                                                   final ResponseStatusCode code, final Iterator itty) {
-        // leaving this overriding the deprecated version of this method because it provides a decent test to those
-        // who might have their own OpProcessor implementations that apply meta-data. leaving this alone helps validate
-        // that the upgrade path is clean.  it can be removed at the next breaking change 3.5.0
-        Map<String, Object> metaData = Collections.emptyMap();
-        if (itty instanceof SideEffectIterator) {
-            final SideEffectIterator traversalIterator = (SideEffectIterator) itty;
-            final String key = traversalIterator.getSideEffectKey();
-            if (key != null) {
-                metaData = new HashMap<>();
-                metaData.put(Tokens.ARGS_SIDE_EFFECT_KEY, key);
-                metaData.put(Tokens.ARGS_AGGREGATE_TO, traversalIterator.getSideEffectAggregator());
-            }
-        } else {
-            // this is a standard traversal iterator
-            metaData = super.generateMetaData(ctx, msg, code, itty);
-        }
-
-        return metaData;
-    }
-
     protected void handleIterator(final Context context, final Iterator itty, final Graph graph) throws InterruptedException {
         final ChannelHandlerContext nettyContext = context.getChannelHandlerContext();
         final RequestMessage msg = context.getRequestMessage();
         final Settings settings = context.getSettings();
-        final MessageSerializer serializer = nettyContext.channel().attr(StateKey.SERIALIZER).get();
+        final MessageSerializer<?> serializer = nettyContext.channel().attr(StateKey.SERIALIZER).get();
         final boolean useBinary = nettyContext.channel().attr(StateKey.USE_BINARY).get();
         boolean warnOnce = false;
 
         // we have an empty iterator - happens on stuff like: g.V().iterate()
         if (!itty.hasNext()) {
             final Map<String, Object> attributes = generateStatusAttributes(nettyContext, msg, ResponseStatusCode.NO_CONTENT, itty, settings);
-            // if it was a g.V().iterate(), then be sure to add the side-effects to the cache
-            if (itty instanceof TraverserIterator &&
-                    !((TraverserIterator)itty).getTraversal().getSideEffects().isEmpty()) {
-                cache.put(msg.getRequestId(), ((TraverserIterator)itty).getTraversal().getSideEffects());
-            }
+
             // as there is nothing left to iterate if we are transaction managed then we should execute a
             // commit here before we send back a NO_CONTENT which implies success
             onTraversalSuccess(graph, context);
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/util/DefaultTemporaryException.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/util/DefaultTemporaryException.java
new file mode 100644
index 0000000..e31a240
--- /dev/null
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/util/DefaultTemporaryException.java
@@ -0,0 +1,49 @@
+/*
+ * 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.server.util;
+
+import org.apache.tinkerpop.gremlin.structure.util.TemporaryException;
+
+/**
+ * This is a default {@link TemporaryException} implementation that server implementers could use if they wished
+ * to indicate retry operations to the client. It is an overly simple class meant more for testing than be extended and
+ * providers are encouraged to tag their own exceptions more directly with the {@link TemporaryException} interface
+ * or to develop their own.
+ */
+public final class DefaultTemporaryException extends Exception implements TemporaryException {
+    public DefaultTemporaryException() {
+    }
+
+    public DefaultTemporaryException(final String message) {
+        super(message);
+    }
+
+    public DefaultTemporaryException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
+
+    public DefaultTemporaryException(final Throwable cause) {
+        super(cause);
+    }
+
+    public DefaultTemporaryException(final String message, final Throwable cause, final boolean enableSuppression,
+                                     final boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+}
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/util/ServerGremlinExecutor.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/util/ServerGremlinExecutor.java
index 67a1608..23c9b5b 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/util/ServerGremlinExecutor.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/util/ServerGremlinExecutor.java
@@ -34,11 +34,15 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 /**
@@ -93,7 +97,10 @@
 
         if (null == gremlinExecutorService) {
             final ThreadFactory threadFactoryGremlin = ThreadFactoryUtil.create("exec-%d");
-            this.gremlinExecutorService = Executors.newFixedThreadPool(settings.gremlinPool, threadFactoryGremlin);
+            final BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(settings.maxWorkQueueSize);
+            this.gremlinExecutorService = new ThreadPoolExecutor(settings.gremlinPool, settings.gremlinPool,
+                    0L, TimeUnit.MILLISECONDS, queue, threadFactoryGremlin,
+                    new ThreadPoolExecutor.AbortPolicy());
         } else {
             this.gremlinExecutorService = gremlinExecutorService;
         }
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/util/SideEffectIterator.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/util/SideEffectIterator.java
deleted file mode 100644
index 2544634..0000000
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/util/SideEffectIterator.java
+++ /dev/null
@@ -1,97 +0,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.
- */
-package org.apache.tinkerpop.gremlin.server.util;
-
-import org.apache.tinkerpop.gremlin.driver.Tokens;
-import org.apache.tinkerpop.gremlin.process.remote.traversal.DefaultRemoteTraverser;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.BulkSet;
-import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
-
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * @author Stephen Mallette (http://stephen.genoprime.com)
- */
-public class SideEffectIterator implements Iterator<Object> {
-
-    private final Iterator<Object> sideEffectIterator;
-    private final String sideEffectKey;
-    private final String sideEffectAggregator;
-
-    public SideEffectIterator(final Object sideEffect, final String sideEffectKey) {
-        this.sideEffectKey = sideEffectKey;
-        sideEffectAggregator = getAggregatorType(sideEffect);
-        sideEffectIterator = sideEffect instanceof BulkSet ?
-                new BulkSetIterator((BulkSet) sideEffect) :
-                IteratorUtils.asIterator(sideEffect);
-    }
-
-    public String getSideEffectKey() {
-        return sideEffectKey;
-    }
-
-    public String getSideEffectAggregator() {
-        return sideEffectAggregator;
-    }
-
-    @Override
-    public boolean hasNext() {
-        return sideEffectIterator.hasNext();
-    }
-
-    @Override
-    public Object next() {
-        return sideEffectIterator.next();
-    }
-
-    private String getAggregatorType(final Object o) {
-        if (o instanceof BulkSet)
-            return Tokens.VAL_AGGREGATE_TO_BULKSET;
-        else if (o instanceof Set)
-            return Tokens.VAL_AGGREGATE_TO_SET;
-        else if (o instanceof Iterable || o instanceof Iterator)
-            return Tokens.VAL_AGGREGATE_TO_LIST;
-        else if (o instanceof Map)
-            return Tokens.VAL_AGGREGATE_TO_MAP;
-        else
-            return Tokens.VAL_AGGREGATE_TO_NONE;
-    }
-
-    static class BulkSetIterator implements Iterator {
-
-        private final Iterator<Map.Entry<Object,Long>> itty;
-
-        public BulkSetIterator(final BulkSet<Object> bulkSet) {
-            itty = bulkSet.asBulk().entrySet().iterator();
-        }
-
-        @Override
-        public boolean hasNext() {
-            return itty.hasNext();
-        }
-
-        @Override
-        public Object next() {
-            final Map.Entry<Object, Long> entry = itty.next();
-            return new DefaultRemoteTraverser<>(entry.getKey(), entry.getValue());
-        }
-    }
-}
\ No newline at end of file
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/driver/ClientConnectionIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/driver/ClientConnectionIntegrateTest.java
index d575778..962cfc2 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/driver/ClientConnectionIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/driver/ClientConnectionIntegrateTest.java
@@ -21,6 +21,7 @@
 import io.netty.handler.codec.CorruptedFrameException;
 import org.apache.log4j.Level;
 import org.apache.log4j.Logger;
+import org.apache.tinkerpop.gremlin.driver.ser.Serializers;
 import org.apache.tinkerpop.gremlin.server.AbstractGremlinServerIntegrationTest;
 import org.apache.tinkerpop.gremlin.server.TestClientFactory;
 import org.apache.tinkerpop.gremlin.util.Log4jRecordingAppender;
@@ -70,6 +71,7 @@
     public void shouldCloseConnectionDeadDueToUnRecoverableError() throws Exception {
         // Set a low value of maxContentLength to intentionally trigger CorruptedFrameException
         final Cluster cluster = TestClientFactory.build()
+                                                 .serializer(Serializers.GRAPHBINARY_V1D0)
                                                  .maxContentLength(64)
                                                  .minConnectionPoolSize(1)
                                                  .maxConnectionPoolSize(2)
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/AbstractRemoteGraphProvider.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/AbstractRemoteGraphProvider.java
index e86a546..7bf2423 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/AbstractRemoteGraphProvider.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/AbstractRemoteGraphProvider.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.driver.remote;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.AbstractGraphProvider;
 import org.apache.tinkerpop.gremlin.LoadGraphWith;
 import org.apache.tinkerpop.gremlin.TestHelper;
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/GraphBinaryRemoteGraphComputerProvider.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/GraphBinaryRemoteGraphComputerProvider.java
index fa07ca3..d6e753d 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/GraphBinaryRemoteGraphComputerProvider.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/GraphBinaryRemoteGraphComputerProvider.java
@@ -57,11 +57,7 @@
         reason = "Mid-traversal V()/E() is currently not supported on GraphComputer")
 @Graph.OptOut(
         test = "org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.InjectTest",
-        method = "g_VX1X_injectXg_VX4XX_out_name",
-        reason = "The inject() step is not supported by GraphComputer")
-@Graph.OptOut(
-        test = "org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.InjectTest",
-        method = "g_VX1X_out_injectXv2X_name",
+        method = "*",
         reason = "The inject() step is not supported by GraphComputer")
 @Graph.OptOut(
         test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.MathTest",
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/GraphSONRemoteGraphComputerProvider.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/GraphSONRemoteGraphComputerProvider.java
index 648de5c..30ecf85 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/GraphSONRemoteGraphComputerProvider.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/GraphSONRemoteGraphComputerProvider.java
@@ -57,11 +57,7 @@
         reason = "Mid-traversal V()/E() is currently not supported on GraphComputer")
 @Graph.OptOut(
         test = "org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.InjectTest",
-        method = "g_VX1X_injectXg_VX4XX_out_name",
-        reason = "The inject() step is not supported by GraphComputer")
-@Graph.OptOut(
-        test = "org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.InjectTest",
-        method = "g_VX1X_out_injectXv2X_name",
+        method = "*",
         reason = "The inject() step is not supported by GraphComputer")
 @Graph.OptOut(
         test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.MathTest",
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/GryoRemoteGraphComputerProvider.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/GryoRemoteGraphComputerProvider.java
index e5c1a4d..6e65989 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/GryoRemoteGraphComputerProvider.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/GryoRemoteGraphComputerProvider.java
@@ -58,11 +58,7 @@
         reason = "Mid-traversal V()/E() is currently not supported on GraphComputer")
 @Graph.OptOut(
         test = "org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.InjectTest",
-        method = "g_VX1X_injectXg_VX4XX_out_name",
-        reason = "The inject() step is not supported by GraphComputer")
-@Graph.OptOut(
-        test = "org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.InjectTest",
-        method = "g_VX1X_out_injectXv2X_name",
+        method = "*",
         reason = "The inject() step is not supported by GraphComputer")
 @Graph.OptOut(
         test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.MathTest",
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GryoRemoteGraphGroovyTranslatorComputerProvider.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GryoRemoteGraphGroovyTranslatorComputerProvider.java
index b594127..2e08aa8 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GryoRemoteGraphGroovyTranslatorComputerProvider.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GryoRemoteGraphGroovyTranslatorComputerProvider.java
@@ -60,11 +60,7 @@
         reason = "Mid-traversal V()/E() is currently not supported on GraphComputer")
 @Graph.OptOut(
         test = "org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.InjectTest",
-        method = "g_VX1X_injectXg_VX4XX_out_name",
-        reason = "The inject() step is not supported by GraphComputer")
-@Graph.OptOut(
-        test = "org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.InjectTest",
-        method = "g_VX1X_out_injectXv2X_name",
+        method = "*",
         reason = "The inject() step is not supported by GraphComputer")
 @Graph.OptOut(
         test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.MathTest",
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/AbstractGremlinServerIntegrationTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/AbstractGremlinServerIntegrationTest.java
index 634063e..e527b1f 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/AbstractGremlinServerIntegrationTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/AbstractGremlinServerIntegrationTest.java
@@ -18,6 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.server;
 
+import org.apache.tinkerpop.gremlin.server.channel.UnifiedChannelizer;
+import org.apache.tinkerpop.gremlin.server.channel.UnifiedChannelizerIntegrateTest;
 import org.apache.tinkerpop.gremlin.server.op.OpLoader;
 import org.junit.After;
 import org.junit.Before;
@@ -83,15 +85,13 @@
 
     @Before
     public void setUp() throws Exception {
-        logger.info("* Testing: " + name.getMethodName());
-        logger.info("* Epoll option enabled:" + GREMLIN_SERVER_EPOLL);
+        logger.info("Starting: " + name.getMethodName());
 
         startServer();
     }
 
     public void setUp(final Settings settings) throws Exception {
-        logger.info("* Testing: " + name.getMethodName());
-        logger.info("* Epoll option enabled:" + GREMLIN_SERVER_EPOLL);
+        logger.info("Starting: " + name.getMethodName());
 
         startServer(settings);
     }
@@ -100,12 +100,17 @@
         if (null == settings) {
             startServer();
         } else {
-            final Settings overridenSettings = overrideSettings(settings);
-            ServerTestHelper.rewritePathsInGremlinServerSettings(overridenSettings);
-            if (GREMLIN_SERVER_EPOLL) {
-                overridenSettings.useEpollEventLoop = true;
+            final Settings oSettings = overrideSettings(settings);
+
+            if (shouldTestUnified()) {
+                oSettings.channelizer = UnifiedChannelizer.class.getName();
             }
-            this.server = new GremlinServer(overridenSettings);
+
+            ServerTestHelper.rewritePathsInGremlinServerSettings(oSettings);
+            if (GREMLIN_SERVER_EPOLL) {
+                oSettings.useEpollEventLoop = true;
+            }
+            this.server = new GremlinServer(oSettings);
             server.start().join();
         }
     }
@@ -119,6 +124,10 @@
             overriddenSettings.useEpollEventLoop = true;
         }
 
+        if (shouldTestUnified()) {
+            overriddenSettings.channelizer = UnifiedChannelizer.class.getName();
+        }
+
         this.server = new GremlinServer(overriddenSettings);
 
         server.start().join();
@@ -127,6 +136,7 @@
     @After
     public void tearDown() throws Exception {
         stopServer();
+        logger.info("Ending: " + name.getMethodName());
     }
 
     public void stopServer() throws Exception {
@@ -138,6 +148,11 @@
         OpLoader.reset();
     }
 
+    protected boolean isUsingUnifiedChannelizer() {
+        return server.getServerGremlinExecutor().
+                getSettings().channelizer.equals(UnifiedChannelizer.class.getName());
+    }
+
     public static boolean deleteDirectory(final File directory) {
         if (directory.exists()) {
             final File[] files = directory.listFiles();
@@ -160,9 +175,16 @@
         try {
             Class.forName("org.neo4j.tinkerpop.api.impl.Neo4jGraphAPIImpl");
             neo4jIncludedForTesting = true;
-        } catch (Exception ex) {
+        } catch (Throwable ex) {
             neo4jIncludedForTesting = false;
         }
         assumeThat("Neo4j implementation was not included for testing - run with -DincludeNeo4j", neo4jIncludedForTesting, is(true));
     }
+
+    private boolean shouldTestUnified() {
+        // ignore all tests in the UnifiedChannelizerIntegrateTest package as they are already rigged to test
+        // over the various channelizer implementations
+        return Boolean.parseBoolean(System.getProperty("testUnified", "false")) &&
+                !this.getClass().getPackage().equals(UnifiedChannelizerIntegrateTest.class.getPackage());
+    }
 }
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/ContextTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/ContextTest.java
index f8956e2..e685932 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/ContextTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/ContextTest.java
@@ -47,7 +47,8 @@
 
     private final ChannelHandlerContext ctx = Mockito.mock(ChannelHandlerContext.class);
     private final RequestMessage request = RequestMessage.build("test").create();
-    private final Context context = new Context(request, ctx, null, null, null, null);
+    private final Settings settings = new Settings();
+    private final Context context = new Context(request, ctx, settings, null, null, null);
     private final Log4jRecordingAppender recordingAppender = new Log4jRecordingAppender();
 
     private Level originalLogLevel;
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java
index 0e03486..7a5d097 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java
@@ -21,7 +21,6 @@
 import org.apache.commons.lang3.exception.ExceptionUtils;
 import org.apache.log4j.Level;
 import org.apache.tinkerpop.gremlin.TestHelper;
-import org.apache.tinkerpop.gremlin.driver.Channelizer;
 import org.apache.tinkerpop.gremlin.driver.Client;
 import org.apache.tinkerpop.gremlin.driver.Cluster;
 import org.apache.tinkerpop.gremlin.driver.RequestOptions;
@@ -34,6 +33,7 @@
 import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
 import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection;
+import org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1;
 import org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0;
 import org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0;
 import org.apache.tinkerpop.gremlin.driver.ser.JsonBuilderGryoSerializer;
@@ -41,7 +41,6 @@
 import org.apache.tinkerpop.gremlin.jsr223.ScriptFileGremlinPlugin;
 import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
-import org.apache.tinkerpop.gremlin.server.channel.NioChannelizer;
 import org.apache.tinkerpop.gremlin.server.handler.OpExecutorHandler;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.structure.io.Storage;
@@ -55,6 +54,7 @@
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mockito;
@@ -168,9 +168,6 @@
                     throw new RuntimeException(ex);
                 }
                 break;
-            case "shouldWorkOverNioTransport":
-                settings.channelizer = NioChannelizer.class.getName();
-                break;
             case "shouldFailWithBadClientSideSerialization":
                 final List<String> custom = Arrays.asList(
                         JsonBuilder.class.getName() + ";" + JsonBuilderGryoSerializer.class.getName(),
@@ -202,9 +199,6 @@
             case "shouldProcessEvalInterruption":
                 settings.evaluationTimeout = 1500;
                 break;
-            case "shouldProcessEvalTimeoutOverride":
-                settings.scriptEvaluationTimeout = 15000;
-                break;
         }
 
         return settings;
@@ -260,25 +254,6 @@
     }
 
     @Test
-    public void shouldProcessEvalTimeoutOverride() throws Exception {
-        final Cluster cluster = TestClientFactory.open();
-        final Client client = cluster.connect();
-        try {
-            final RequestOptions options = RequestOptions.build().timeout(500).create();
-
-            try {
-                client.submit("Thread.sleep(5000);'done'", options).all().get();
-                fail("Should have timed out");
-            } catch (Exception ex) {
-                final ResponseException re = (ResponseException) ex.getCause();
-                assertEquals(ResponseStatusCode.SERVER_ERROR_TIMEOUT, re.getResponseStatusCode());
-            }
-        } finally {
-            cluster.close();
-        }
-    }
-
-    @Test
     public void shouldProcessTraversalInterruption() throws Exception {
         final Cluster cluster = TestClientFactory.open();
         final Client client = cluster.connect();
@@ -421,6 +396,7 @@
     }
 
     @Test
+    @Ignore("This test had some bad semantics that allowed it to pass even though it was technically failing")
     public void shouldEventuallySucceedOnSameServerWithDefault() throws Exception {
         stopServer();
 
@@ -438,6 +414,8 @@
 
             startServer();
 
+            boolean succeedAtLeastOnce = false;
+
             // default reconnect time is 1 second so wait some extra time to be sure it has time to try to bring it
             // back to life. usually this passes on the first attempt, but docker is sometimes slow and we get failures
             // waiting for Gremlin Server to pop back up
@@ -446,12 +424,15 @@
                 try {
                     final int result = client.submit("1+1").all().join().get(0).getInt();
                     assertEquals(2, result);
+                    succeedAtLeastOnce = true;
                     break;
                 } catch (Exception ignored) {
                     logger.warn("Attempt {} failed on shouldEventuallySucceedOnSameServerWithDefault", ix);
                 }
             }
 
+            assertThat(succeedAtLeastOnce, is(true));
+
         } finally {
             cluster.close();
         }
@@ -584,9 +565,8 @@
         final Cluster cluster = TestClientFactory.open();
         final Client client = cluster.connect();
         try {
-            final ResultSet results = client.submit("1/0");
-
             try {
+                final ResultSet results = client.submit("1/0");
                 results.all().join();
                 fail("Should have thrown exception over bad serialization");
             } catch (Exception ex) {
@@ -597,7 +577,7 @@
                 final ResponseException rex = (ResponseException) inner;
                 assertEquals("java.lang.ArithmeticException", rex.getRemoteExceptionHierarchy().get().get(0));
                 assertEquals(1, rex.getRemoteExceptionHierarchy().get().size());
-                assertThat(rex.getRemoteStackTrace().get(), startsWith("java.lang.ArithmeticException: Division by zero\n\tat java.math.BigDecimal.divide(BigDecimal.java"));
+                assertThat(rex.getRemoteStackTrace().get(), containsString("Division by zero"));
             }
 
             // should not die completely just because we had a bad serialization error.  that kind of stuff happens
@@ -698,27 +678,6 @@
     }
 
     @Test
-    public void shouldWorkOverNioTransport() throws Exception {
-        final Cluster cluster = TestClientFactory.build().channelizer(Channelizer.NioChannelizer.class.getName()).create();
-        final Client client = cluster.connect();
-
-        try {
-            final AtomicInteger checked = new AtomicInteger(0);
-            final ResultSet results = client.submit("[1,2,3,4,5,6,7,8,9]");
-            while (!results.allItemsAvailable()) {
-                assertTrue(results.getAvailableItemCount() < 10);
-                checked.incrementAndGet();
-                Thread.sleep(100);
-            }
-
-            assertTrue(checked.get() > 0);
-            assertEquals(9, results.getAvailableItemCount());
-        } finally {
-            cluster.close();
-        }
-    }
-
-    @Test
     public void shouldStream() throws Exception {
         final Cluster cluster = TestClientFactory.open();
         final Client client = cluster.connect();
@@ -941,6 +900,24 @@
     }
 
     @Test
+    public void shouldSerializeToStringWhenRequestedGraphBinaryV1() throws Exception {
+        final Map<String, Object> m = new HashMap<>();
+        m.put("serializeResultToString", true);
+        final GraphBinaryMessageSerializerV1 serializer = new GraphBinaryMessageSerializerV1();
+        serializer.configure(m, null);
+
+        final Cluster cluster = TestClientFactory.build().serializer(serializer).create();
+        final Client client = cluster.connect();
+
+        final ResultSet resultSet = client.submit("TinkerFactory.createClassic()");
+        final List<Result> results = resultSet.all().join();
+        assertEquals(1, results.size());
+        assertEquals("tinkergraph[vertices:6 edges:6]", results.get(0).getString());
+
+        cluster.close();
+    }
+
+    @Test
     public void shouldSerializeToStringWhenRequestedGryoV1() throws Exception {
         final Map<String, Object> m = new HashMap<>();
         m.put("serializeResultToString", true);
@@ -1082,12 +1059,11 @@
         final Client client = cluster.connect();
 
         try {
-            final Instant now = Instant.now();
-            final List<Result> r = client.submit("java.time.Instant.ofEpochMilli(" + now.toEpochMilli() + ")").all().join();
+            final List<Result> r = client.submit("java.time.Instant.EPOCH").all().join();
             assertEquals(1, r.size());
 
             final Instant then = r.get(0).get(Instant.class);
-            assertEquals(now, then);
+            assertEquals(Instant.EPOCH, then);
         } finally {
             cluster.close();
         }
@@ -1120,12 +1096,11 @@
         final Client client = cluster.connect();
 
         try {
-            final Instant now = Instant.now();
-            final List<Result> r = client.submit("java.time.Instant.ofEpochMilli(" + now.toEpochMilli() + ")").all().join();
+            final List<Result> r = client.submit("java.time.Instant.EPOCH").all().join();
             assertEquals(1, r.size());
 
             final Instant then = r.get(0).get(Instant.class);
-            assertEquals(now, then);
+            assertEquals(Instant.EPOCH, then);
         } finally {
             cluster.close();
         }
@@ -1254,18 +1229,18 @@
         final Cluster cluster = TestClientFactory.open();
         final Client client = cluster.connect(name.getMethodName());
 
-        final Vertex vertexBeforeTx = client.submit("v=graph.addVertex(\"name\",\"stephen\")").all().get().get(0).getVertex();
-        assertEquals("stephen", vertexBeforeTx.values("name").next());
+        final Vertex vertexBeforeTx = client.submit("v=g.addV(\"person\").property(\"name\",\"stephen\").next()").all().get().get(0).getVertex();
+        assertEquals("person", vertexBeforeTx.label());
 
-        final Vertex vertexFromV = client.submit("graph.vertices().next()").all().get().get(0).getVertex();
-        assertEquals("stephen", vertexFromV.values("name").next());
+        final String nameValueFromV = client.submit("g.V().values('name').next()").all().get().get(0).getString();
+        assertEquals("stephen", nameValueFromV);
 
         final Vertex vertexFromBinding = client.submit("v").all().get().get(0).getVertex();
-        assertEquals("stephen", vertexFromBinding.values("name").next());
+        assertEquals("person", vertexFromBinding.label());
 
-        final Vertex vertexAfterTx = client.submit("v.property(\"color\",\"blue\"); graph.tx().commit(); v").all().get().get(0).getVertex();
-        assertEquals("stephen", vertexAfterTx.values("name").next());
-        assertEquals("blue", vertexAfterTx.values("color").next());
+        final Map<String,Object> vertexAfterTx = client.submit("g.V(v).property(\"color\",\"blue\").iterate(); g.tx().commit(); g.V(v).valueMap().by(unfold())").all().get().get(0).get(Map.class);
+        assertEquals("stephen", vertexAfterTx.get("name"));
+        assertEquals("blue", vertexAfterTx.get("color"));
 
         cluster.close();
     }
@@ -1280,29 +1255,29 @@
         client.submit("graph.tx().onReadWrite(Transaction.READ_WRITE_BEHAVIOR.MANUAL);null").all().get();
         client.submit("graph.tx().open()").all().get();
 
-        final Vertex vertexBeforeTx = client.submit("v=graph.addVertex(\"name\",\"stephen\")").all().get().get(0).getVertex();
-        assertEquals("stephen", vertexBeforeTx.values("name").next());
+        final Vertex vertexBeforeTx = client.submit("v=g.addV(\"person\").property(\"name\", \"stephen\").next()").all().get().get(0).getVertex();
+        assertEquals("person", vertexBeforeTx.label());
 
-        final Vertex vertexFromV = client.submit("graph.vertices().next()").all().get().get(0).getVertex();
-        assertEquals("stephen", vertexFromV.values("name").next());
+        final String nameValueFromV = client.submit("g.V().values(\"name\").next()").all().get().get(0).getString();
+        assertEquals("stephen", nameValueFromV);
 
         final Vertex vertexFromBinding = client.submit("v").all().get().get(0).getVertex();
-        assertEquals("stephen", vertexFromBinding.values("name").next());
+        assertEquals("person", vertexFromBinding.label());
 
-        client.submit("v.property(\"color\",\"blue\")").all().get();
-        client.submit("graph.tx().commit()").all().get();
+        client.submit("g.V(v).property(\"color\",\"blue\")").all().get();
+        client.submit("g.tx().commit()").all().get();
 
         // Run a sessionless request to change transaction.readWriteConsumer back to AUTO
         // The will make the next in session request fail if consumers aren't ThreadLocal
-        sessionlessClient.submit("graph.vertices().next()").all().get();
+        sessionlessClient.submit("g.V().next()").all().get();
 
-        client.submit("graph.tx().open()").all().get();
+        client.submit("g.tx().open()").all().get();
 
-        final Vertex vertexAfterTx = client.submit("graph.vertices().next()").all().get().get(0).getVertex();
-        assertEquals("stephen", vertexAfterTx.values("name").next());
-        assertEquals("blue", vertexAfterTx.values("color").next());
+        final Map<String,Object> vertexAfterTx = client.submit("g.V().valueMap().by(unfold())").all().get().get(0).get(Map.class);
+        assertEquals("stephen", vertexAfterTx.get("name"));
+        assertEquals("blue", vertexAfterTx.get("color"));
 
-        client.submit("graph.tx().rollback()").all().get();
+        client.submit("g.tx().rollback()").all().get();
 
         cluster.close();
     }
@@ -1317,20 +1292,20 @@
             final Client sessionlessClient = cluster.connect();
 
             //open transaction in session, then add vertex and commit
-            sessionClient.submit("graph.tx().open()").all().get();
-            final Vertex vertexBeforeTx = sessionClient.submit("v=graph.addVertex(\"name\",\"stephen\")").all().get().get(0).getVertex();
-            assertEquals("stephen", vertexBeforeTx.values("name").next());
-            sessionClient.submit("graph.tx().commit()").all().get();
+            sessionClient.submit("g.tx().open()").all().get();
+            final Vertex vertexBeforeTx = sessionClient.submit("v=g.addV(\"person\").property(\"name\",\"stephen\").next()").all().get().get(0).getVertex();
+            assertEquals("person", vertexBeforeTx.label());
+            sessionClient.submit("g.tx().commit()").all().get();
 
             // check that session transaction is closed
-            final boolean isOpen = sessionClient.submit("graph.tx().isOpen()").all().get().get(0).getBoolean();
+            final boolean isOpen = sessionClient.submit("g.tx().isOpen()").all().get().get(0).getBoolean();
             assertTrue("Transaction should be closed", !isOpen);
 
             //run a sessionless read
-            sessionlessClient.submit("graph.traversal().V()").all().get();
+            sessionlessClient.submit("g.V()").all().get();
 
             // check that session transaction is still closed
-            final boolean isOpenAfterSessionless = sessionClient.submit("graph.tx().isOpen()").all().get().get(0).getBoolean();
+            final boolean isOpenAfterSessionless = sessionClient.submit("g.tx().isOpen()").all().get().get(0).getBoolean();
             assertTrue("Transaction should stil be closed", !isOpenAfterSessionless);
         } finally {
             cluster.close();
@@ -1527,8 +1502,8 @@
         }
 
         final Client rebound = cluster.connect().alias("graph");
-        final Vertex v = rebound.submit("g.addVertex('name','jason')").all().get().get(0).getVertex();
-        assertEquals("jason", v.value("name"));
+        final Vertex v = rebound.submit("g.addVertex(T.label,'person')").all().get().get(0).getVertex();
+        assertEquals("person", v.label());
 
         cluster.close();
     }
@@ -1539,28 +1514,27 @@
         final Client client = cluster.connect();
 
         try {
-            client.submit("g.addVertex('name','stephen');").all().get().get(0).getVertex();
+            client.submit("g.addVertex(label,'person','name','stephen');").all().get().get(0).getVertex();
             fail("Should have tossed an exception because \"g\" does not have the addVertex method under default config");
         } catch (Exception ex) {
             final Throwable root = ExceptionUtils.getRootCause(ex);
             assertThat(root, instanceOf(ResponseException.class));
             final ResponseException re = (ResponseException) root;
-            assertEquals(ResponseStatusCode.SERVER_ERROR_SCRIPT_EVALUATION, re.getResponseStatusCode());
+            assertEquals(ResponseStatusCode.SERVER_ERROR_EVALUATION, re.getResponseStatusCode());
         }
 
         final Client rebound = cluster.connect().alias("graph");
-        final Vertex v = rebound.submit("g.addVertex('name','jason')").all().get().get(0).getVertex();
-        assertEquals("jason", v.value("name"));
+        final Vertex v = rebound.submit("g.addVertex(label,'person','name','jason')").all().get().get(0).getVertex();
+        assertEquals("person", v.label());
 
         cluster.close();
     }
 
     @Test
     public void shouldAliasTraversalSourceVariables() throws Exception {
-        final Cluster cluster = TestClientFactory.open();
+        final Cluster cluster = TestClientFactory.build().serializer(Serializers.GRYO_V3D0).create();
         final Client client = cluster.connect();
         try {
-
             try {
                 client.submit("g.addV().property('name','stephen')").all().get().get(0).getVertex();
                 fail("Should have tossed an exception because \"g\" is readonly in this context");
@@ -1568,7 +1542,7 @@
                 final Throwable root = ExceptionUtils.getRootCause(ex);
                 assertThat(root, instanceOf(ResponseException.class));
                 final ResponseException re = (ResponseException) root;
-                assertEquals(ResponseStatusCode.SERVER_ERROR_SCRIPT_EVALUATION, re.getResponseStatusCode());
+                assertEquals(ResponseStatusCode.SERVER_ERROR_EVALUATION, re.getResponseStatusCode());
             }
 
             final Client clientAliased = client.alias("g1");
@@ -1581,7 +1555,7 @@
 
     @Test
     public void shouldAliasGraphVariablesInSession() throws Exception {
-        final Cluster cluster = TestClientFactory.open();
+        final Cluster cluster = TestClientFactory.build().serializer(Serializers.GRYO_V3D0).create();
         final Client client = cluster.connect(name.getMethodName());
 
         try {
@@ -1591,20 +1565,23 @@
             final Throwable root = ExceptionUtils.getRootCause(ex);
             assertThat(root, instanceOf(ResponseException.class));
             final ResponseException re = (ResponseException) root;
-            assertEquals(ResponseStatusCode.SERVER_ERROR_SCRIPT_EVALUATION, re.getResponseStatusCode());
+            assertEquals(ResponseStatusCode.SERVER_ERROR_EVALUATION, re.getResponseStatusCode());
+            client.close();
         }
 
-        final Client aliased = client.alias("graph");
-        assertEquals("jason", aliased.submit("n='jason'").all().get().get(0).getString());
-        final Vertex v = aliased.submit("g.addVertex('name',n)").all().get().get(0).getVertex();
-        assertEquals("jason", v.value("name"));
-
-        cluster.close();
+        try {
+            final Client aliased = cluster.connect(name.getMethodName()).alias("graph");
+            assertEquals("jason", aliased.submit("n='jason'").all().get().get(0).getString());
+            final Vertex v = aliased.submit("g.addVertex('name',n)").all().get().get(0).getVertex();
+            assertEquals("jason", v.value("name"));
+        } finally {
+            cluster.close();
+        }
     }
 
     @Test
     public void shouldAliasTraversalSourceVariablesInSession() throws Exception {
-        final Cluster cluster = TestClientFactory.open();
+        final Cluster cluster = TestClientFactory.build().serializer(Serializers.GRYO_V3D0).create();
         final Client client = cluster.connect(name.getMethodName());
 
         try {
@@ -1614,7 +1591,7 @@
             final Throwable root = ExceptionUtils.getRootCause(ex);
             assertThat(root, instanceOf(ResponseException.class));
             final ResponseException re = (ResponseException) root;
-            assertEquals(ResponseStatusCode.SERVER_ERROR_SCRIPT_EVALUATION, re.getResponseStatusCode());
+            assertEquals(ResponseStatusCode.SERVER_ERROR_EVALUATION, re.getResponseStatusCode());
         }
 
         final Client clientAliased = client.alias("g1");
@@ -1668,7 +1645,10 @@
         final Cluster cluster = TestClientFactory.open();
 
         try {
-            final Client client = cluster.connect(name.getMethodName());
+            // this configures the client to behave like OpProcessor for UnifiedChannelizer
+            final Client.SessionSettings settings = Client.SessionSettings.build().
+                    sessionId(name.getMethodName()).maintainStateAfterException(true).create();
+            final Client client = cluster.connect(Client.Settings.build().useSession(settings).create());
 
             for (int index = 0; index < 50; index++) {
                 final CompletableFuture<ResultSet> first = client.submitAsync(
@@ -1710,6 +1690,18 @@
         }
     }
 
+    private void assertFutureTimeout(final CompletableFuture<List<Result>> f) {
+        try {
+            f.get();
+            fail("Should have timed out");
+        } catch (Exception ex) {
+            final Throwable root = ExceptionUtils.getRootCause(ex);
+            assertThat(root, instanceOf(ResponseException.class));
+            assertEquals(ResponseStatusCode.SERVER_ERROR_TIMEOUT, ((ResponseException) root).getResponseStatusCode());
+            assertThat(root.getMessage(), allOf(startsWith("Evaluation exceeded"), containsString("250 ms")));
+        }
+    }
+
     @Test
     public void shouldCloseAllClientsOnCloseOfCluster() throws Exception {
         final Cluster cluster = TestClientFactory.open();
@@ -1735,7 +1727,7 @@
         } catch (Exception ex) {
             final Throwable root = ExceptionUtils.getRootCause(ex);
             assertThat(root, instanceOf(IllegalStateException.class));
-            assertEquals("Client has been closed", root.getMessage());
+            assertEquals("Client is closed", root.getMessage());
         }
 
         try {
@@ -1744,7 +1736,7 @@
         } catch (Exception ex) {
             final Throwable root = ExceptionUtils.getRootCause(ex);
             assertThat(root, instanceOf(IllegalStateException.class));
-            assertEquals("Client has been closed", root.getMessage());
+            assertEquals("Client is closed", root.getMessage());
         }
 
         try {
@@ -1753,7 +1745,7 @@
         } catch (Exception ex) {
             final Throwable root = ExceptionUtils.getRootCause(ex);
             assertThat(root, instanceOf(IllegalStateException.class));
-            assertEquals("Client has been closed", root.getMessage());
+            assertEquals("Client is closed", root.getMessage());
         }
 
         try {
@@ -1762,7 +1754,7 @@
         } catch (Exception ex) {
             final Throwable root = ExceptionUtils.getRootCause(ex);
             assertThat(root, instanceOf(IllegalStateException.class));
-            assertEquals("Client has been closed", root.getMessage());
+            assertEquals("Client is closed", root.getMessage());
         }
 
         try {
@@ -1771,7 +1763,7 @@
         } catch (Exception ex) {
             final Throwable root = ExceptionUtils.getRootCause(ex);
             assertThat(root, instanceOf(IllegalStateException.class));
-            assertEquals("Client has been closed", root.getMessage());
+            assertEquals("Client is closed", root.getMessage());
         }
 
         // allow call to close() even though closed through cluster
@@ -1835,20 +1827,6 @@
 
     }
 
-    private void assertFutureTimeout(final CompletableFuture<List<Result>> futureFirst) {
-        try
-        {
-            futureFirst.get();
-            fail("Should have timed out");
-        }
-        catch (Exception ex)
-        {
-            final Throwable root = ExceptionUtils.getRootCause(ex);
-            assertThat(root, instanceOf(ResponseException.class));
-            assertThat(root.getMessage(), startsWith("Evaluation exceeded the configured 'evaluationTimeout' threshold of 250 ms"));
-        }
-    }
-
     @Test
     public void shouldClusterReadFileFromResources() throws Exception {
         final Cluster cluster = Cluster.open(TestClientFactory.RESOURCE_PATH);
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinResultSetIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinResultSetIntegrateTest.java
index bd46679..770854a 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinResultSetIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinResultSetIntegrateTest.java
@@ -38,6 +38,7 @@
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
 import org.apache.tinkerpop.gremlin.structure.io.IoTest;
+import org.apache.tinkerpop.gremlin.structure.io.binary.GraphBinaryMapper;
 import org.apache.tinkerpop.gremlin.structure.util.reference.ReferenceEdge;
 import org.apache.tinkerpop.gremlin.structure.util.reference.ReferencePath;
 import org.apache.tinkerpop.gremlin.structure.util.reference.ReferenceProperty;
@@ -45,6 +46,7 @@
 import org.apache.tinkerpop.gremlin.structure.util.reference.ReferenceVertexProperty;
 import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
 import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3d0;
+import org.apache.tinkerpop.shaded.kryo.Kryo;
 import org.hamcrest.CoreMatchers;
 import org.junit.After;
 import org.junit.Before;
@@ -76,22 +78,22 @@
 
     @Parameterized.Parameters(name = "{0}")
     public static Iterable<Object[]> data() {
-        final MessageSerializer graphBinaryMessageSerializerV1 = new GraphBinaryMessageSerializerV1();
+        final MessageSerializer<GraphBinaryMapper> graphBinaryMessageSerializerV1 = new GraphBinaryMessageSerializerV1();
 
         // must configure Gryo with "custom" since it's configured on the server
-        final MessageSerializer gryoMessageSerializerV3d0 = new GryoMessageSerializerV3d0();
+        final MessageSerializer<Kryo> gryoMessageSerializerV3d0 = new GryoMessageSerializerV3d0();
         final Map<String,Object> gryoV3d0Config = new HashMap<>();
         gryoV3d0Config.put("ioRegistries", Collections.singletonList(TinkerIoRegistryV3d0.class.getName()));
         gryoV3d0Config.put("custom", Collections.singletonList("groovy.json.JsonBuilder;org.apache.tinkerpop.gremlin.driver.ser.JsonBuilderGryoSerializer"));
         gryoMessageSerializerV3d0.configure(gryoV3d0Config, null);
 
-        final MessageSerializer gryoMessageSerializerV1d0 = new GryoMessageSerializerV1d0();
+        final MessageSerializer<Kryo> gryoMessageSerializerV1d0 = new GryoMessageSerializerV1d0();
         final Map<String,Object> gryoV1d0Config = new HashMap<>();
         gryoV1d0Config.put("ioRegistries", Collections.singletonList(TinkerIoRegistryV3d0.class.getName()));
         gryoV1d0Config.put("custom", Collections.singletonList("groovy.json.JsonBuilder;org.apache.tinkerpop.gremlin.driver.ser.JsonBuilderGryoSerializer"));
         gryoMessageSerializerV1d0.configure(gryoV1d0Config, null);
 
-        final MessageSerializer gryoLiteMessageSerializerV1d0 = new GryoLiteMessageSerializerV1d0();
+        final MessageSerializer<Kryo> gryoLiteMessageSerializerV1d0 = new GryoLiteMessageSerializerV1d0();
         final Map<String,Object> gryoLiteV1d0Config = new HashMap<>();
         gryoLiteV1d0Config.put("ioRegistries", Collections.singletonList(TinkerIoRegistryV3d0.class.getName()));
         gryoLiteV1d0Config.put("custom", Collections.singletonList("groovy.json.JsonBuilder;org.apache.tinkerpop.gremlin.driver.ser.JsonBuilderGryoSerializer"));
@@ -109,7 +111,7 @@
     public Serializers name;
 
     @Parameterized.Parameter(value = 1)
-    public MessageSerializer messageSerializer;
+    public MessageSerializer<?> messageSerializer;
 
     @Before
     public void beforeTest() {
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuditLogDeprecatedIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuditLogDeprecatedIntegrateTest.java
new file mode 100644
index 0000000..b337991
--- /dev/null
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuditLogDeprecatedIntegrateTest.java
@@ -0,0 +1,386 @@
+/*
+ * 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.server;
+
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+import org.apache.log4j.Logger;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.tinkerpop.gremlin.driver.Client;
+import org.apache.tinkerpop.gremlin.driver.Cluster;
+import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection;
+import org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.server.auth.AllowAllAuthenticator;
+import org.apache.tinkerpop.gremlin.server.auth.Krb5Authenticator;
+import org.apache.tinkerpop.gremlin.server.auth.SimpleAuthenticator;
+import org.apache.tinkerpop.gremlin.server.channel.HttpChannelizer;
+import org.apache.tinkerpop.gremlin.server.handler.SaslAndHttpBasicAuthenticationHandler;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONTokens;
+import org.apache.tinkerpop.gremlin.util.Log4jRecordingAppender;
+import org.apache.tinkerpop.shaded.jackson.databind.JsonNode;
+import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
+import org.junit.Test;
+import org.slf4j.LoggerFactory;
+
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Stream;
+
+import static org.apache.log4j.Level.INFO;
+import static org.apache.tinkerpop.gremlin.server.GremlinServer.AUDIT_LOGGER_NAME;
+import static org.apache.tinkerpop.gremlin.server.GremlinServerAuthKrb5IntegrateTest.TESTCONSOLE;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test audit logs. Like other descendants of AbstractGremlinServerIntegrationTest this test suite assumes that
+ * tests are run sequentially and thus the server and kdcServer variables can be reused.
+ *
+ * @author Marc de Lignie
+ */
+public class GremlinServerAuditLogDeprecatedIntegrateTest extends AbstractGremlinServerIntegrationTest {
+    private static final org.slf4j.Logger logger = LoggerFactory.getLogger(GremlinServerAuditLogDeprecatedIntegrateTest.class);
+    private Log4jRecordingAppender recordingAppender = null;
+
+    private final ObjectMapper mapper = new ObjectMapper();
+    private final Base64.Encoder encoder = Base64.getUrlEncoder();
+
+    private static final boolean AUDIT_LOG_ENABLED = true;
+    private static final boolean AUDIT_LOG_DISABLED = false;
+    private static final String TESTCONSOLE2 = "GremlinConsole2";
+
+    private KdcFixture kdcServer;
+
+    @Override
+    public void setUp() throws Exception {
+        recordingAppender = new Log4jRecordingAppender();
+        final Logger rootLogger = Logger.getRootLogger();
+        rootLogger.addAppender(recordingAppender);
+
+        try {
+            final String moduleBaseDir = System.getProperty("basedir", ".");
+            final String authConfigName = moduleBaseDir + "/src/test/resources/org/apache/tinkerpop/gremlin/server/gremlin-console-jaas.conf";
+            System.setProperty("java.security.auth.login.config", authConfigName);
+            kdcServer = new KdcFixture(moduleBaseDir);
+            kdcServer.setUp();
+        } catch(Exception ex)  {
+            logger.warn(String.format("Could not start Kerberos Server for %s", name.getMethodName()), ex);
+        }
+        super.setUp();
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        final Logger rootLogger = Logger.getRootLogger();
+        rootLogger.removeAppender(recordingAppender);
+        kdcServer.close();
+        System.clearProperty("java.security.auth.login.config");
+        super.tearDown();
+    }
+
+    /**
+     * Configure specific Gremlin Server settings for specific tests.
+     */
+    @Override
+    public Settings overrideSettings(final Settings settings) {
+        settings.host = kdcServer.gremlinHostname;
+        final Settings.SslSettings sslConfig = new Settings.SslSettings();
+        sslConfig.enabled = false;
+        settings.ssl = sslConfig;
+        final Settings.AuthenticationSettings authSettings = new Settings.AuthenticationSettings();
+        settings.authentication = authSettings;
+        authSettings.enableAuditLog = AUDIT_LOG_ENABLED;
+        authSettings.authenticator = Krb5Authenticator.class.getName();
+        final Map<String,Object> authConfig = new HashMap<>();
+        authSettings.config = authConfig;
+
+        final String nameOfTest = name.getMethodName();
+        switch (nameOfTest) {
+            case "shouldAuditLogWithAllowAllAuthenticator":
+                authSettings.authenticator = AllowAllAuthenticator.class.getName();
+                break;
+            case "shouldAuditLogWithTraversalOp":
+            case "shouldAuditLogWithSimpleAuthenticator":
+                authSettings.authenticator = SimpleAuthenticator.class.getName();
+                authConfig.put(SimpleAuthenticator.CONFIG_CREDENTIALS_DB, "conf/tinkergraph-credentials.properties");
+                break;
+            case "shouldNotAuditLogWhenDisabled":
+                authSettings.enableAuditLog = AUDIT_LOG_DISABLED;
+            case "shouldAuditLogWithKrb5Authenticator":
+            case "shouldAuditLogTwoClientsWithKrb5Authenticator":
+                authConfig.put("keytab", kdcServer.serviceKeytabFile.getAbsolutePath());
+                authConfig.put("principal", kdcServer.serverPrincipal);
+                break;
+            case "shouldAuditLogWithHttpTransport":
+                settings.host = "localhost";
+                settings.channelizer = HttpChannelizer.class.getName();
+                authSettings.authenticator = SimpleAuthenticator.class.getName();
+                authSettings.authenticationHandler = SaslAndHttpBasicAuthenticationHandler.class.getName();
+                authConfig.put(SimpleAuthenticator.CONFIG_CREDENTIALS_DB, "conf/tinkergraph-credentials.properties");
+                break;
+        }
+        return settings;
+    }
+
+    @Test
+    public void shouldAuditLogWithAllowAllAuthenticator() throws Exception {
+
+        final Cluster cluster = TestClientFactory.build(kdcServer.gremlinHostname).create();
+        final Client client = cluster.connect();
+
+        try {
+            assertEquals(2, client.submit("1+1").all().get().get(0).getInt());
+            assertEquals(3, client.submit("1+2").all().get().get(0).getInt());
+            assertEquals(4, client.submit("1+3").all().get().get(0).getInt());
+        } finally {
+            cluster.close();
+        }
+
+        // wait for logger to flush - (don't think there is a way to detect this)
+        stopServer();
+        Thread.sleep(1000);
+
+        // WebSocketChannelizer does not add SaslAuthenticationHandler for AllowAllAuthenticator,
+        // so no authenticated user log line available
+        assertTrue(recordingAppender.logMatchesAny(AUDIT_LOGGER_NAME, INFO, "User with address .+? requested: 1\\+1"));
+        assertTrue(recordingAppender.logMatchesAny(AUDIT_LOGGER_NAME, INFO, "User with address .+? requested: 1\\+2"));
+        assertTrue(recordingAppender.logMatchesAny(AUDIT_LOGGER_NAME, INFO, "User with address .+? requested: 1\\+3"));
+    }
+
+    @Test
+    public void shouldAuditLogWithSimpleAuthenticator() throws Exception {
+        final String username = "stephen";
+        final String password = "password";
+
+        final Cluster cluster = TestClientFactory.build(kdcServer.gremlinHostname).credentials(username, password).create();
+        final Client client = cluster.connect();
+
+        try {
+            assertEquals(2, client.submit("1+1").all().get().get(0).getInt());
+            assertEquals(3, client.submit("1+2").all().get().get(0).getInt());
+            assertEquals(4, client.submit("1+3").all().get().get(0).getInt());
+            assertEquals(5, client.submit("1+4").all().get().get(0).getInt());
+        } finally {
+            cluster.close();
+        }
+
+        // wait for logger to flush - (don't think there is a way to detect this)
+        stopServer();
+        Thread.sleep(1000);
+
+        final String simpleAuthenticatorName = SimpleAuthenticator.class.getSimpleName();
+
+        final List<LoggingEvent> log = recordingAppender.getEvents();
+        final Stream<LoggingEvent> auditEvents = log.stream().filter(event -> event.getLoggerName().equals(AUDIT_LOGGER_NAME));
+        final LoggingEvent authEvent = auditEvents
+                .filter(event -> event.getMessage().toString().contains(simpleAuthenticatorName)).iterator().next();
+        final String authMsg = authEvent.getMessage().toString();
+        assertTrue(authEvent.getLevel() == INFO &&
+                authMsg.matches(String.format("User %s with address .+? authenticated by %s", username, simpleAuthenticatorName)));
+        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
+                item.getMessage().toString().matches("User with address .+? requested: 1\\+1")));
+        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
+                item.getMessage().toString().matches("User with address .+? requested: 1\\+2")));
+        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
+                item.getMessage().toString().matches("User with address .+? requested: 1\\+3")));
+    }
+
+    @Test
+    public void shouldAuditLogWithKrb5Authenticator() throws Exception {
+        final Cluster cluster = TestClientFactory.build(kdcServer.gremlinHostname).jaasEntry(TESTCONSOLE)
+                .protocol(kdcServer.serverPrincipalName).create();
+        final Client client = cluster.connect();
+        try {
+            assertEquals(2, client.submit("1+1").all().get().get(0).getInt());
+            assertEquals(3, client.submit("1+2").all().get().get(0).getInt());
+            assertEquals(4, client.submit("1+3").all().get().get(0).getInt());
+        } finally {
+            cluster.close();
+        }
+
+        // wait for logger to flush - (don't think there is a way to detect this)
+        stopServer();
+        Thread.sleep(1000);
+
+        final List<LoggingEvent> log = recordingAppender.getEvents();
+        final Stream<LoggingEvent> auditEvents = log.stream().filter(event -> event.getLoggerName().equals(AUDIT_LOGGER_NAME));
+        final LoggingEvent authEvent = auditEvents
+                .filter(event -> event.getMessage().toString().contains("Krb5Authenticator")).iterator().next();
+        final String authMsg = authEvent.getMessage().toString();
+        assertTrue(authEvent.getLevel() == INFO &&
+                authMsg.matches(String.format("User %s with address .+? authenticated by Krb5Authenticator", kdcServer.clientPrincipalName)));
+        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
+                item.getMessage().toString().matches("User with address .+? requested: 1\\+1")));
+        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
+                item.getMessage().toString().matches("User with address .+? requested: 1\\+2")));
+        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
+                item.getMessage().toString().matches("User with address .+? requested: 1\\+3")));
+    }
+
+    @Test
+    public void shouldNotAuditLogWhenDisabled() throws Exception {
+        final Cluster cluster = TestClientFactory.build(kdcServer.gremlinHostname).jaasEntry(TESTCONSOLE)
+                .protocol(kdcServer.serverPrincipalName).create();
+        final Client client = cluster.connect();
+        try {
+            assertEquals(2, client.submit("1+1").all().get().get(0).getInt());
+            assertEquals(3, client.submit("1+2").all().get().get(0).getInt());
+            assertEquals(4, client.submit("1+3").all().get().get(0).getInt());
+        } finally {
+            cluster.close();
+        }
+
+        // wait for logger to flush - (don't think there is a way to detect this)
+        stopServer();
+        Thread.sleep(1000);
+
+        final List<LoggingEvent> log = recordingAppender.getEvents();
+        assertFalse(log.stream().anyMatch(item -> item.getLevel() == INFO &&
+                item.getMessage().toString().matches("User drankye with address .+? authenticated by Krb5Authenticator")));
+        assertFalse(log.stream().anyMatch(item -> item.getLevel() == INFO &&
+                item.getMessage().toString().matches("User with address .+? requested: 1\\+1")));
+        assertFalse(log.stream().anyMatch(item -> item.getLevel() == INFO &&
+                item.getMessage().toString().matches("User with address .+? requested: 1\\+2")));
+        assertFalse(log.stream().anyMatch(item -> item.getLevel() == INFO &&
+            item.getMessage().toString().matches("User with address .+? requested: 1\\+3")));
+    }
+
+    @Test
+    public void shouldAuditLogWithHttpTransport() throws Exception {
+        final CloseableHttpClient httpclient = HttpClients.createDefault();
+        final HttpGet httpget = new HttpGet(TestClientFactory.createURLString("?gremlin=1-1"));
+        httpget.addHeader("Authorization", "Basic " + encoder.encodeToString("stephen:password".getBytes()));
+
+        try (final CloseableHttpResponse response = httpclient.execute(httpget)) {
+            assertEquals(200, response.getStatusLine().getStatusCode());
+            assertEquals("application/json", response.getEntity().getContentType().getValue());
+            final String json = EntityUtils.toString(response.getEntity());
+            final JsonNode node = mapper.readTree(json);
+            assertEquals(0, node.get("result").get("data").get(GraphSONTokens.VALUEPROP).get(0).intValue());
+        }
+
+        // wait for logger to flush - (don't think there is a way to detect this)
+        stopServer();
+        Thread.sleep(1000);
+
+        final String simpleAuthenticatorName = SimpleAuthenticator.class.getSimpleName();
+
+        final List<LoggingEvent> log = recordingAppender.getEvents();
+        final Stream<LoggingEvent> auditEvents = log.stream().filter(event -> event.getLoggerName().equals(AUDIT_LOGGER_NAME));
+        final LoggingEvent authEvent = auditEvents
+                .filter(event -> event.getMessage().toString().contains(simpleAuthenticatorName)).iterator().next();
+        final String authMsg = authEvent.getMessage().toString();
+        assertTrue(authEvent.getLevel() == INFO &&
+                authMsg.matches(String.format("User stephen with address .+? authenticated by %s", simpleAuthenticatorName)));
+        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
+                item.getMessage().toString().matches("User with address .+? requested: 1-1")));
+    }
+
+    @Test
+    public void shouldAuditLogWithTraversalOp() throws Exception {
+        final String username = "stephen";
+        final String password = "password";
+
+        final Cluster cluster = TestClientFactory.build(kdcServer.gremlinHostname).credentials(username, password).create();
+        final GraphTraversalSource g = AnonymousTraversalSource.traversal().
+                withRemote(DriverRemoteConnection.using(cluster, "gmodern"));
+
+        try {
+            assertEquals(6, g.V().count().next().intValue());
+        } finally {
+            cluster.close();
+        }
+
+        // wait for logger to flush - (don't think there is a way to detect this)
+        stopServer();
+        Thread.sleep(1000);
+
+        final String simpleAuthenticatorName = SimpleAuthenticator.class.getSimpleName();
+
+        final List<LoggingEvent> log = recordingAppender.getEvents();
+        final Stream<LoggingEvent> auditEvents = log.stream().filter(event -> event.getLoggerName().equals(AUDIT_LOGGER_NAME));
+        final LoggingEvent authEvent = auditEvents
+                .filter(event -> event.getMessage().toString().contains(simpleAuthenticatorName)).iterator().next();
+        final String authMsg = authEvent.getMessage().toString();
+        assertTrue(authEvent.getLevel() == INFO &&
+                authMsg.matches(String.format("User %s with address .+? authenticated by %s", username, simpleAuthenticatorName)));
+        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
+                item.getMessage().toString().matches("User with address .+? requested: \\[\\[], \\[V\\(\\), count\\(\\)]]")));
+    }
+
+    @Test
+    public void shouldAuditLogTwoClientsWithKrb5Authenticator() throws Exception {
+        // calling init to make sure the clusters get their connections primed in low resource environments like travis
+        final Cluster cluster = TestClientFactory.build(kdcServer.gremlinHostname).jaasEntry(TESTCONSOLE).
+                protocol(kdcServer.serverPrincipalName).create();
+        final Client client = cluster.connect();
+        client.init();
+
+        final Cluster cluster2 = TestClientFactory.build(kdcServer.gremlinHostname).jaasEntry(TESTCONSOLE2).
+                protocol(kdcServer.serverPrincipalName).create();
+        final Client client2 = cluster2.connect();
+        client2.init();
+
+        try {
+            assertEquals(2, client.submit("1+1").all().get().get(0).getInt());
+            assertEquals(22, client2.submit("11+11").all().get().get(0).getInt());
+            assertEquals(3, client.submit("1+2").all().get().get(0).getInt());
+            assertEquals(23, client2.submit("11+12").all().get().get(0).getInt());
+            assertEquals(24, client2.submit("11+13").all().get().get(0).getInt());
+            assertEquals(4, client.submit("1+3").all().get().get(0).getInt());
+        } finally {
+            cluster.close();
+            cluster2.close();
+        }
+
+        // wait for logger to flush - (don't think there is a way to detect this)
+        stopServer();
+        Thread.sleep(1000);
+
+        final List<LoggingEvent> log = recordingAppender.getEvents();
+        final Stream<LoggingEvent> auditEvents = log.stream().filter(event -> event.getLoggerName().equals(AUDIT_LOGGER_NAME));
+        final LoggingEvent authEvent = auditEvents
+                .filter(event -> event.getMessage().toString().contains("Krb5Authenticator")).iterator().next();
+        final String authMsg = authEvent.getMessage().toString();
+        assertTrue(authEvent.getLevel() == INFO &&
+                authMsg.matches(String.format("User %s with address .+? authenticated by Krb5Authenticator", kdcServer.clientPrincipalName)));
+        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
+                item.getMessage().toString().matches("User with address .+? requested: 1\\+1")));
+        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
+                item.getMessage().toString().matches("User with address .+? requested: 1\\+2")));
+        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
+                item.getMessage().toString().matches("User with address .+? requested: 1\\+3")));
+
+        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
+                item.getMessage().toString().matches(String.format("User %s with address .+? authenticated by Krb5Authenticator", kdcServer.clientPrincipalName2))));
+        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
+                item.getMessage().toString().matches("User with address .+? requested: 11\\+11")));
+        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
+                item.getMessage().toString().matches("User with address .+? requested: 11\\+12")));
+        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
+                item.getMessage().toString().matches("User with address .+? requested: 11\\+13")));
+    }
+}
\ No newline at end of file
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuditLogIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuditLogIntegrateTest.java
index 74fcc42..bc981ed 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuditLogIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuditLogIntegrateTest.java
@@ -25,20 +25,21 @@
 import org.apache.http.util.EntityUtils;
 import org.apache.log4j.Logger;
 import org.apache.log4j.spi.LoggingEvent;
-import org.apache.tinkerpop.gremlin.driver.Channelizer;
 import org.apache.tinkerpop.gremlin.driver.Client;
 import org.apache.tinkerpop.gremlin.driver.Cluster;
+import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection;
+import org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
 import org.apache.tinkerpop.gremlin.server.auth.AllowAllAuthenticator;
+import org.apache.tinkerpop.gremlin.server.auth.AuthenticatedUser;
 import org.apache.tinkerpop.gremlin.server.auth.Krb5Authenticator;
 import org.apache.tinkerpop.gremlin.server.auth.SimpleAuthenticator;
 import org.apache.tinkerpop.gremlin.server.channel.HttpChannelizer;
-import org.apache.tinkerpop.gremlin.server.channel.NioChannelizer;
+import org.apache.tinkerpop.gremlin.server.handler.SaslAndHttpBasicAuthenticationHandler;
 import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONTokens;
 import org.apache.tinkerpop.gremlin.util.Log4jRecordingAppender;
 import org.apache.tinkerpop.shaded.jackson.databind.JsonNode;
 import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Test;
 import org.slf4j.LoggerFactory;
 
@@ -56,7 +57,7 @@
 import static org.junit.Assert.assertTrue;
 
 /**
- * Test audit logs  and like other descendants of AbstractGremlinServerIntegrationTest this test suite assumes that
+ * Test audit logs. Like other descendants of AbstractGremlinServerIntegrationTest this test suite assumes that
  * tests are run sequentially and thus the server and kdcServer variables can be reused.
  *
  * @author Marc de Lignie
@@ -74,7 +75,6 @@
 
     private KdcFixture kdcServer;
 
-    @Before
     @Override
     public void setUp() throws Exception {
         recordingAppender = new Log4jRecordingAppender();
@@ -82,9 +82,10 @@
         rootLogger.addAppender(recordingAppender);
 
         try {
-            final String buildDir = System.getProperty("build.dir");
-            kdcServer = new KdcFixture(buildDir +
-                    "/test-classes/org/apache/tinkerpop/gremlin/server/gremlin-console-jaas.conf");
+            final String moduleBaseDir = System.getProperty("basedir", ".");
+            final String authConfigName = moduleBaseDir + "/src/test/resources/org/apache/tinkerpop/gremlin/server/gremlin-console-jaas.conf";
+            System.setProperty("java.security.auth.login.config", authConfigName);
+            kdcServer = new KdcFixture(moduleBaseDir);
             kdcServer.setUp();
         } catch(Exception ex)  {
             logger.warn(String.format("Could not start Kerberos Server for %s", name.getMethodName()), ex);
@@ -92,12 +93,12 @@
         super.setUp();
     }
 
-    @After
     @Override
     public void tearDown() throws Exception {
         final Logger rootLogger = Logger.getRootLogger();
         rootLogger.removeAppender(recordingAppender);
         kdcServer.close();
+        System.clearProperty("java.security.auth.login.config");
         super.tearDown();
     }
 
@@ -106,13 +107,13 @@
      */
     @Override
     public Settings overrideSettings(final Settings settings) {
-        settings.host = kdcServer.hostname;
+        settings.host = kdcServer.gremlinHostname;
         final Settings.SslSettings sslConfig = new Settings.SslSettings();
         sslConfig.enabled = false;
         settings.ssl = sslConfig;
         final Settings.AuthenticationSettings authSettings = new Settings.AuthenticationSettings();
         settings.authentication = authSettings;
-        authSettings.enableAuditLog = AUDIT_LOG_ENABLED;
+        settings.enableAuditLog = AUDIT_LOG_ENABLED;
         authSettings.authenticator = Krb5Authenticator.class.getName();
         final Map<String,Object> authConfig = new HashMap<>();
         authSettings.config = authConfig;
@@ -122,26 +123,23 @@
             case "shouldAuditLogWithAllowAllAuthenticator":
                 authSettings.authenticator = AllowAllAuthenticator.class.getName();
                 break;
+            case "shouldAuditLogWithTraversalOp":
             case "shouldAuditLogWithSimpleAuthenticator":
                 authSettings.authenticator = SimpleAuthenticator.class.getName();
                 authConfig.put(SimpleAuthenticator.CONFIG_CREDENTIALS_DB, "conf/tinkergraph-credentials.properties");
                 break;
             case "shouldNotAuditLogWhenDisabled":
-                authSettings.enableAuditLog = AUDIT_LOG_DISABLED;
+                settings.enableAuditLog = AUDIT_LOG_DISABLED;
             case "shouldAuditLogWithKrb5Authenticator":
             case "shouldAuditLogTwoClientsWithKrb5Authenticator":
                 authConfig.put("keytab", kdcServer.serviceKeytabFile.getAbsolutePath());
                 authConfig.put("principal", kdcServer.serverPrincipal);
                 break;
-            case "shouldAuditLogWithNioTransport":
-                settings.channelizer = NioChannelizer.class.getName();
-                authConfig.put("keytab", kdcServer.serviceKeytabFile.getAbsolutePath());
-                authConfig.put("principal", kdcServer.serverPrincipal);
-                break;
             case "shouldAuditLogWithHttpTransport":
                 settings.host = "localhost";
                 settings.channelizer = HttpChannelizer.class.getName();
                 authSettings.authenticator = SimpleAuthenticator.class.getName();
+                authSettings.authenticationHandler = SaslAndHttpBasicAuthenticationHandler.class.getName();
                 authConfig.put(SimpleAuthenticator.CONFIG_CREDENTIALS_DB, "conf/tinkergraph-credentials.properties");
                 break;
         }
@@ -151,7 +149,7 @@
     @Test
     public void shouldAuditLogWithAllowAllAuthenticator() throws Exception {
 
-        final Cluster cluster = TestClientFactory.build(kdcServer.hostname).create();
+        final Cluster cluster = TestClientFactory.build(kdcServer.gremlinHostname).create();
         final Client client = cluster.connect();
 
         try {
@@ -168,9 +166,12 @@
 
         // WebSocketChannelizer does not add SaslAuthenticationHandler for AllowAllAuthenticator,
         // so no authenticated user log line available
-        assertTrue(recordingAppender.logMatchesAny(AUDIT_LOGGER_NAME, INFO, "User with address .*? requested: 1\\+1"));
-        assertTrue(recordingAppender.logMatchesAny(AUDIT_LOGGER_NAME, INFO, "User with address .*? requested: 1\\+2"));
-        assertTrue(recordingAppender.logMatchesAny(AUDIT_LOGGER_NAME, INFO, "User with address .*? requested: 1\\+3"));
+        assertTrue(recordingAppender.logMatchesAny(AUDIT_LOGGER_NAME, INFO, String.format(
+                "User %s with address .+? requested: 1\\+1", AuthenticatedUser.ANONYMOUS_USERNAME)));
+        assertTrue(recordingAppender.logMatchesAny(AUDIT_LOGGER_NAME, INFO, String.format(
+                "User %s with address .+? requested: 1\\+2", AuthenticatedUser.ANONYMOUS_USERNAME)));
+        assertTrue(recordingAppender.logMatchesAny(AUDIT_LOGGER_NAME, INFO, String.format(
+                "User %s with address .+? requested: 1\\+3", AuthenticatedUser.ANONYMOUS_USERNAME)));
     }
 
     @Test
@@ -178,7 +179,7 @@
         final String username = "stephen";
         final String password = "password";
 
-        final Cluster cluster = TestClientFactory.build(kdcServer.hostname).credentials(username, password).create();
+        final Cluster cluster = TestClientFactory.build(kdcServer.gremlinHostname).credentials(username, password).create();
         final Client client = cluster.connect();
 
         try {
@@ -202,19 +203,18 @@
                 .filter(event -> event.getMessage().toString().contains(simpleAuthenticatorName)).iterator().next();
         final String authMsg = authEvent.getMessage().toString();
         assertTrue(authEvent.getLevel() == INFO &&
-                authMsg.matches(String.format("User %s with address .*? authenticated by %s", username, simpleAuthenticatorName)));
+                authMsg.matches(String.format("User %s with address .+? authenticated by %s", username, simpleAuthenticatorName)));
         assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .*? requested: 1\\+1")));
+                item.getMessage().toString().matches("User stephen with address .+? requested: 1\\+1")));
         assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .*? requested: 1\\+2")));
+                item.getMessage().toString().matches("User stephen with address .+? requested: 1\\+2")));
         assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .*? requested: 1\\+3")));
+                item.getMessage().toString().matches("User stephen with address .+? requested: 1\\+3")));
     }
 
     @Test
     public void shouldAuditLogWithKrb5Authenticator() throws Exception {
-        final Cluster cluster = TestClientFactory.build(kdcServer.hostname).jaasEntry(TESTCONSOLE)
-                .protocol(kdcServer.serverPrincipalName).create();
+        final Cluster cluster = TestClientFactory.build(kdcServer.gremlinHostname).jaasEntry(TESTCONSOLE).protocol(kdcServer.serverPrincipalName).create();
         final Client client = cluster.connect();
         try {
             assertEquals(2, client.submit("1+1").all().get().get(0).getInt());
@@ -234,19 +234,18 @@
                 .filter(event -> event.getMessage().toString().contains("Krb5Authenticator")).iterator().next();
         final String authMsg = authEvent.getMessage().toString();
         assertTrue(authEvent.getLevel() == INFO &&
-                authMsg.matches(String.format("User %s with address .*? authenticated by Krb5Authenticator", kdcServer.clientPrincipalName)));
+                authMsg.matches(String.format("User %s with address .+? authenticated by Krb5Authenticator", kdcServer.clientPrincipalName)));
         assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .*? requested: 1\\+1")));
+                item.getMessage().toString().matches("User drankye with address .+? requested: 1\\+1")));
         assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .*? requested: 1\\+2")));
+                item.getMessage().toString().matches("User drankye with address .+? requested: 1\\+2")));
         assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .*? requested: 1\\+3")));
+                item.getMessage().toString().matches("User drankye with address .+? requested: 1\\+3")));
     }
 
     @Test
     public void shouldNotAuditLogWhenDisabled() throws Exception {
-        final Cluster cluster = TestClientFactory.build(kdcServer.hostname).jaasEntry(TESTCONSOLE)
-                .protocol(kdcServer.serverPrincipalName).create();
+        final Cluster cluster = TestClientFactory.build(kdcServer.gremlinHostname).jaasEntry(TESTCONSOLE).protocol(kdcServer.serverPrincipalName).create();
         final Client client = cluster.connect();
         try {
             assertEquals(2, client.submit("1+1").all().get().get(0).getInt());
@@ -262,46 +261,13 @@
 
         final List<LoggingEvent> log = recordingAppender.getEvents();
         assertFalse(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User .*? with address .*? authenticated by Krb5Authenticator")));
+                item.getMessage().toString().matches("User drankye with address .+? authenticated by Krb5Authenticator")));
         assertFalse(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .*? requested: 1\\+1")));
+                item.getMessage().toString().matches("User drankye with address .+? requested: 1\\+1")));
         assertFalse(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .*? requested: 1\\+2")));
+                item.getMessage().toString().matches("User drankye with address .+? requested: 1\\+2")));
         assertFalse(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-            item.getMessage().toString().matches("User with address .*? requested: 1\\+3")));
-    }
-
-    @Test
-    public void shouldAuditLogWithNioTransport() throws Exception {
-        final Cluster cluster = TestClientFactory.build(kdcServer.hostname).
-                channelizer(Channelizer.NioChannelizer.class.getName()).
-                jaasEntry(TESTCONSOLE).protocol(kdcServer.serverPrincipalName).create();
-        final Client client = cluster.connect();
-        try {
-            assertEquals(2, client.submit("1+1").all().get().get(0).getInt());
-            assertEquals(3, client.submit("1+2").all().get().get(0).getInt());
-            assertEquals(4, client.submit("1+3").all().get().get(0).getInt());
-        } finally {
-            cluster.close();
-        }
-
-        // wait for logger to flush - (don't think there is a way to detect this)
-        stopServer();
-        Thread.sleep(1000);
-
-        final List<LoggingEvent> log = recordingAppender.getEvents();
-        final Stream<LoggingEvent> auditEvents = log.stream().filter(event -> event.getLoggerName().equals(AUDIT_LOGGER_NAME));
-        final LoggingEvent authEvent = auditEvents
-                .filter(event -> event.getMessage().toString().contains("Krb5Authenticator")).iterator().next();
-        final String authMsg = authEvent.getMessage().toString();
-        assertTrue(authEvent.getLevel() == INFO &&
-                authMsg.matches(String.format("User %s with address .*? authenticated by Krb5Authenticator", kdcServer.clientPrincipalName)));
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .*? requested: 1\\+1")));
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .*? requested: 1\\+2")));
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .*? requested: 1\\+3")));
+            item.getMessage().toString().matches("User drankye with address .+? requested: 1\\+3")));
     }
 
     @Test
@@ -330,21 +296,53 @@
                 .filter(event -> event.getMessage().toString().contains(simpleAuthenticatorName)).iterator().next();
         final String authMsg = authEvent.getMessage().toString();
         assertTrue(authEvent.getLevel() == INFO &&
-                authMsg.matches(String.format("User %s with address .*? authenticated by %s", "stephen", simpleAuthenticatorName)));
+                authMsg.matches(String.format("User stephen with address .+? authenticated by %s", simpleAuthenticatorName)));
         assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .*? requested: 2-1")));
+                item.getMessage().toString().matches("User stephen with address .+? requested: 2-1")));
+    }
+
+    @Test
+    public void shouldAuditLogWithTraversalOp() throws Exception {
+        final String username = "stephen";
+        final String password = "password";
+
+        final Cluster cluster = TestClientFactory.build(kdcServer.gremlinHostname).credentials(username, password).create();
+        final GraphTraversalSource g = AnonymousTraversalSource.traversal().
+                withRemote(DriverRemoteConnection.using(cluster, "gmodern"));
+
+        try {
+            assertEquals(6, g.V().count().next().intValue());
+        } finally {
+            cluster.close();
+        }
+
+        // wait for logger to flush - (don't think there is a way to detect this)
+        stopServer();
+        Thread.sleep(1000);
+
+        final String simpleAuthenticatorName = SimpleAuthenticator.class.getSimpleName();
+
+        final List<LoggingEvent> log = recordingAppender.getEvents();
+        final Stream<LoggingEvent> auditEvents = log.stream().filter(event -> event.getLoggerName().equals(AUDIT_LOGGER_NAME));
+        final LoggingEvent authEvent = auditEvents
+                .filter(event -> event.getMessage().toString().contains(simpleAuthenticatorName)).iterator().next();
+        final String authMsg = authEvent.getMessage().toString();
+        assertTrue(authEvent.getLevel() == INFO &&
+                authMsg.matches(String.format("User %s with address .+? authenticated by %s", username, simpleAuthenticatorName)));
+        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
+                item.getMessage().toString().matches("User .+? with address .+? requested: \\[\\[], \\[V\\(\\), count\\(\\)]]")));
     }
 
     @Test
     public void shouldAuditLogTwoClientsWithKrb5Authenticator() throws Exception {
         // calling init to make sure the clusters get their connections primed in low resource environments like travis
-        final Cluster cluster = TestClientFactory.build(kdcServer.hostname).jaasEntry(TESTCONSOLE)
-                .protocol(kdcServer.serverPrincipalName).create();
+        final Cluster cluster = TestClientFactory.build(kdcServer.gremlinHostname).jaasEntry(TESTCONSOLE).
+                protocol(kdcServer.serverPrincipalName).create();
         final Client client = cluster.connect();
         client.init();
 
-        final Cluster cluster2 = TestClientFactory.build(kdcServer.hostname).jaasEntry(TESTCONSOLE2)
-                .protocol(kdcServer.serverPrincipalName).create();
+        final Cluster cluster2 = TestClientFactory.build(kdcServer.gremlinHostname).jaasEntry(TESTCONSOLE2).
+                protocol(kdcServer.serverPrincipalName).create();
         final Client client2 = cluster2.connect();
         client2.init();
 
@@ -370,21 +368,21 @@
                 .filter(event -> event.getMessage().toString().contains("Krb5Authenticator")).iterator().next();
         final String authMsg = authEvent.getMessage().toString();
         assertTrue(authEvent.getLevel() == INFO &&
-                authMsg.matches(String.format("User %s with address .*? authenticated by Krb5Authenticator", kdcServer.clientPrincipalName)));
+                authMsg.matches(String.format("User %s with address .+? authenticated by Krb5Authenticator", kdcServer.clientPrincipalName)));
         assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .*? requested: 1\\+1")));
+                item.getMessage().toString().matches("User drankye with address .+? requested: 1\\+1")));
         assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .*? requested: 1\\+2")));
+                item.getMessage().toString().matches("User drankye with address .+? requested: 1\\+2")));
         assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .*? requested: 1\\+3")));
+                item.getMessage().toString().matches("User drankye with address .+? requested: 1\\+3")));
 
         assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches(String.format("User %s with address .*? authenticated by Krb5Authenticator", kdcServer.clientPrincipalName2))));
+                item.getMessage().toString().matches(String.format("User %s with address .+? authenticated by Krb5Authenticator", kdcServer.clientPrincipalName2))));
         assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .*? requested: 11\\+11")));
+                item.getMessage().toString().matches("User drankye2 with address .+? requested: 11\\+11")));
         assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .*? requested: 11\\+12")));
+                item.getMessage().toString().matches("User drankye2 with address .+? requested: 11\\+12")));
         assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .*? requested: 11\\+13")));
+                item.getMessage().toString().matches("User drankye2 with address .+? requested: 11\\+13")));
     }
 }
\ No newline at end of file
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthIntegrateTest.java
index f1740c4..c4db8b2 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthIntegrateTest.java
@@ -57,7 +57,7 @@
         final Settings.AuthenticationSettings authSettings = new Settings.AuthenticationSettings();
         authSettings.authenticator = SimpleAuthenticator.class.getName();
 
-        // use a credentials graph with one user in it: stephen/password
+        // use a credentials graph with two users in it: stephen/password and marko/rainbow-dash
         final Map<String,Object> authConfig = new HashMap<>();
         authConfig.put(SimpleAuthenticator.CONFIG_CREDENTIALS_DB, "conf/tinkergraph-credentials.properties");
 
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthKrb5IntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthKrb5IntegrateTest.java
index 669029e..2244fb6 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthKrb5IntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthKrb5IntegrateTest.java
@@ -30,8 +30,6 @@
 import org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0;
 import org.apache.tinkerpop.gremlin.server.auth.Krb5Authenticator;
 import org.ietf.jgss.GSSException;
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Test;
 import org.slf4j.LoggerFactory;
 
@@ -57,7 +55,6 @@
     private KdcFixture kdcServer;
     private Level previousLogLevel;
 
-    @Before
     @Override
     public void setUp() throws Exception {
         // this logger is noisy for travis and we don't assert anything and the error is already tracked on
@@ -68,9 +65,10 @@
         handlerLogger.setLevel(Level.OFF);
 
         try {
-            final String buildDir = System.getProperty("build.dir");
-            kdcServer = new KdcFixture(buildDir +
-                    "/test-classes/org/apache/tinkerpop/gremlin/server/gremlin-console-jaas.conf");
+            final String projectBaseDir = System.getProperty("basedir", ".");
+            final String authConfigName = projectBaseDir + "/src/test/resources/org/apache/tinkerpop/gremlin/server/gremlin-console-jaas.conf";
+            System.setProperty("java.security.auth.login.config", authConfigName);
+            kdcServer = new KdcFixture(projectBaseDir);
             kdcServer.setUp();
         } catch(Exception e)  {
             logger.warn(e.getMessage());
@@ -78,11 +76,15 @@
         super.setUp();
     }
 
-    @After
-    public void teardownForEachTest() {
+    @Override
+    public void tearDown() throws Exception {
         final org.apache.log4j.Logger handlerLogger = org.apache.log4j.Logger.getLogger(
                 "org.apache.tinkerpop.gremlin.driver.Handler$GremlinResponseHandler");
         handlerLogger.setLevel(previousLogLevel);
+
+        kdcServer.close();
+        System.clearProperty("java.security.auth.login.config");
+        super.tearDown();
     }
 
     /**
@@ -90,7 +92,7 @@
      */
     @Override
     public Settings overrideSettings(final Settings settings) {
-        settings.host = kdcServer.hostname;
+        settings.host = kdcServer.gremlinHostname;
         final Settings.SslSettings sslConfig = new Settings.SslSettings();
         sslConfig.enabled = false;
         settings.ssl = sslConfig;
@@ -136,7 +138,7 @@
 
     @Test
     public void shouldAuthenticateWithDefaults() throws Exception {
-        final Cluster cluster = TestClientFactory.build(kdcServer.hostname).jaasEntry(TESTCONSOLE)
+        final Cluster cluster = TestClientFactory.build(kdcServer.gremlinHostname).jaasEntry(TESTCONSOLE)
                 .protocol(kdcServer.serverPrincipalName).create();
         final Client client = cluster.connect();
         assertConnection(cluster, client);
@@ -144,8 +146,8 @@
 
     @Test
     public void shouldFailWithoutClientJaasEntry() {
-        final Cluster cluster = TestClientFactory.build(kdcServer.hostname).
-                protocol(kdcServer.serverPrincipalName).create();
+        final Cluster cluster = TestClientFactory.build(kdcServer.gremlinHostname)
+                .protocol(kdcServer.serverPrincipalName).create();
         final Client client = cluster.connect();
         try {
             client.submit("1+1").all().get();
@@ -160,7 +162,7 @@
 
     @Test
     public void shouldFailWithoutClientTicketCache() {
-        final Cluster cluster = TestClientFactory.build(kdcServer.hostname).jaasEntry(TESTCONSOLE_NOT_LOGGED_IN)
+        final Cluster cluster = TestClientFactory.build(kdcServer.gremlinHostname).jaasEntry(TESTCONSOLE_NOT_LOGGED_IN)
                 .protocol(kdcServer.serverPrincipalName).create();
         final Client client = cluster.connect();
         try {
@@ -193,7 +195,7 @@
     public void shouldAuthenticateWithQop() throws Exception {
         final String oldQop = System.getProperty("javax.security.sasl.qop", "");
         System.setProperty("javax.security.sasl.qop", "auth-conf");
-        final Cluster cluster = TestClientFactory.build(kdcServer.hostname).jaasEntry(TESTCONSOLE)
+        final Cluster cluster = TestClientFactory.build(kdcServer.gremlinHostname).jaasEntry(TESTCONSOLE)
                 .protocol(kdcServer.serverPrincipalName).create();
         final Client client = cluster.connect();
         try {
@@ -208,8 +210,8 @@
 
     @Test
     public void shouldAuthenticateWithSsl() throws Exception {
-        final Cluster cluster = TestClientFactory.build(kdcServer.hostname).jaasEntry(TESTCONSOLE).enableSsl(true).
-                sslSkipCertValidation(true).protocol(kdcServer.serverPrincipalName).create();
+        final Cluster cluster = TestClientFactory.build(kdcServer.gremlinHostname).jaasEntry(TESTCONSOLE).enableSsl(true).sslSkipCertValidation(true)
+                .protocol(kdcServer.serverPrincipalName).create();
         final Client client = cluster.connect();
         assertConnection(cluster, client);
     }
@@ -229,11 +231,11 @@
         assertAuthViaToStringWithSpecifiedSerializer(new GraphBinaryMessageSerializerV1());
     }
 
-    public void assertAuthViaToStringWithSpecifiedSerializer(final MessageSerializer serializer) throws InterruptedException, ExecutionException {
+    public void assertAuthViaToStringWithSpecifiedSerializer(final MessageSerializer<?> serializer) throws InterruptedException, ExecutionException {
         final Map<String,Object> config = new HashMap<>();
         config.put("serializeResultToString", true);
         serializer.configure(config, null);
-        final Cluster cluster = TestClientFactory.build(kdcServer.hostname).jaasEntry(TESTCONSOLE)
+        final Cluster cluster = TestClientFactory.build(kdcServer.gremlinHostname).jaasEntry(TESTCONSOLE)
                 .protocol(kdcServer.serverPrincipalName).serializer(serializer).create();
         final Client client = cluster.connect();
         assertConnection(cluster, client);
@@ -253,7 +255,7 @@
      * Tries to force the logger to flush fully or at least wait until it does.
      */
     private void assertFailedLogin() {
-        final Cluster cluster = TestClientFactory.build(kdcServer.hostname).jaasEntry(TESTCONSOLE)
+        final Cluster cluster = TestClientFactory.build(kdcServer.gremlinHostname).jaasEntry(TESTCONSOLE)
                 .protocol(kdcServer.serverPrincipalName).create();
         final Client client = cluster.connect();
         try {
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthzIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthzIntegrateTest.java
new file mode 100644
index 0000000..00eacda
--- /dev/null
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthzIntegrateTest.java
@@ -0,0 +1,389 @@
+/*
+ * 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.server;
+
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+import org.apache.log4j.Logger;
+import org.apache.tinkerpop.gremlin.driver.Client;
+import org.apache.tinkerpop.gremlin.driver.Cluster;
+import org.apache.tinkerpop.gremlin.driver.exception.ResponseException;
+import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
+import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection;
+import org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.server.auth.AllowAllAuthenticator;
+import org.apache.tinkerpop.gremlin.server.auth.SimpleAuthenticator;
+import org.apache.tinkerpop.gremlin.server.authz.AllowListAuthorizer;
+import org.apache.tinkerpop.gremlin.server.channel.HttpChannelizer;
+import org.apache.tinkerpop.gremlin.server.handler.SaslAndHttpBasicAuthenticationHandler;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONTokens;
+import org.apache.tinkerpop.gremlin.util.Log4jRecordingAppender;
+import org.apache.tinkerpop.gremlin.util.function.Lambda;
+import org.apache.tinkerpop.shaded.jackson.databind.JsonNode;
+import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
+import org.junit.Test;
+
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.Objects;
+
+import static org.apache.log4j.Level.INFO;
+import static org.apache.tinkerpop.gremlin.server.GremlinServer.AUDIT_LOGGER_NAME;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * Run with:
+ * mvn verify -Dit.test=GremlinServerAuthzIntegrateTest -pl gremlin-server -DskipTests -DskipIntegrationTests=false -Dmaven.javadoc.skip=true -Dorg.slf4j.simpleLogger.defaultLogLevel=info
+ *
+ * @author Marc de Lignie
+ */
+public class GremlinServerAuthzIntegrateTest extends AbstractGremlinServerIntegrationTest {
+
+    private Log4jRecordingAppender recordingAppender;
+    private final ObjectMapper mapper = new ObjectMapper();
+    private final Base64.Encoder encoder = Base64.getUrlEncoder();
+
+    @Override
+    public void setUp() throws Exception {
+        recordingAppender = new Log4jRecordingAppender();
+        final Logger rootLogger = Logger.getRootLogger();
+        rootLogger.addAppender(recordingAppender);
+        super.setUp();
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        super.tearDown();
+        final Logger rootLogger = Logger.getRootLogger();
+        rootLogger.removeAppender(recordingAppender);
+        super.tearDown();
+    }
+
+    /**
+     * Configure Gremlin Server settings per test.
+     */
+    @Override
+    public Settings overrideSettings(final Settings settings) {
+        final Settings.SslSettings sslConfig = new Settings.SslSettings();
+        sslConfig.enabled = false;
+
+        final Settings.AuthenticationSettings authSettings = new Settings.AuthenticationSettings();
+        authSettings.config = new HashMap<>();
+        authSettings.authenticator = SimpleAuthenticator.class.getName();
+        authSettings.config.put(SimpleAuthenticator.CONFIG_CREDENTIALS_DB, "conf/tinkergraph-credentials.properties");
+
+        final Settings.AuthorizationSettings authzSettings = new Settings.AuthorizationSettings();
+        authzSettings.authorizer = AllowListAuthorizer.class.getName();
+        authzSettings.config = new HashMap<>();
+        final String yamlName = "org/apache/tinkerpop/gremlin/server/allow-list.yaml";
+        final String yamlHttpName = "org/apache/tinkerpop/gremlin/server/allow-list-http-anonymous.yaml";
+        final String file = Objects.requireNonNull(getClass().getClassLoader().getResource(yamlName)).getFile();
+        authzSettings.config.put(AllowListAuthorizer.KEY_AUTHORIZATION_ALLOWLIST, file);
+
+        settings.ssl = sslConfig;
+        settings.authentication = authSettings;
+        settings.authorization = authzSettings;
+        settings.enableAuditLog = true;
+
+        final String nameOfTest = name.getMethodName();
+        switch (nameOfTest) {
+            case "shouldFailBytecodeRequestWithAllowAllAuthenticator":
+            case "shouldFailStringRequestWithAllowAllAuthenticator":
+                authSettings.authenticator = AllowAllAuthenticator.class.getName();
+                break;
+            case "shouldAuthorizeWithHttpTransport":
+            case "shouldFailAuthorizeWithHttpTransport":
+            case "shouldKeepAuthorizingWithHttpTransport":
+                settings.channelizer = HttpChannelizer.class.getName();
+                authSettings.authenticationHandler = SaslAndHttpBasicAuthenticationHandler.class.getName();
+                break;
+            case "shouldAuthorizeWithAllowAllAuthenticatorAndHttpTransport":
+                settings.channelizer = HttpChannelizer.class.getName();
+                authSettings.authenticator = AllowAllAuthenticator.class.getName();
+                authSettings.authenticationHandler = SaslAndHttpBasicAuthenticationHandler.class.getName();
+                authSettings.config = null;
+                final String fileHttp = Objects.requireNonNull(getClass().getClassLoader().getResource(yamlHttpName)).getFile();
+                authzSettings.config.put(AllowListAuthorizer.KEY_AUTHORIZATION_ALLOWLIST, fileHttp);
+                break;
+        }
+        return settings;
+    }
+
+    @Test
+    public void shouldAuthorizeBytecodeRequest() {
+        final Cluster cluster = TestClientFactory.build().credentials("stephen", "password").create();
+        final GraphTraversalSource g = AnonymousTraversalSource.traversal().withRemote(
+                DriverRemoteConnection.using(cluster, "gmodern"));
+
+        try {
+            assertEquals(6, (long) g.V().count().next());
+        } finally {
+            cluster.close();
+        }
+    }
+
+    @Test
+    public void shouldAuthorizeBytecodeRequestWithLambda() {
+        final Cluster cluster = TestClientFactory.build().credentials("marko", "rainbow-dash").create();
+        final GraphTraversalSource g = AnonymousTraversalSource.traversal().withRemote(
+                DriverRemoteConnection.using(cluster, "gclassic"));
+
+        try {
+            assertEquals(6, (long) g.V().count().next());
+            assertEquals(6, (long) g.V().map(Lambda.function("it.get().value('name')")).count().next());
+        } finally {
+            cluster.close();
+        }
+    }
+
+    @Test
+    public void shouldFailBytecodeRequestWithLambda() throws Exception{
+        final Cluster cluster = TestClientFactory.build().credentials("stephen", "password").create();
+        final GraphTraversalSource g = AnonymousTraversalSource.traversal().withRemote(
+                DriverRemoteConnection.using(cluster, "gmodern"));
+
+        try {
+            g.V().map(Lambda.function("it.get().value('name')")).count().next();
+            fail("Authorization for bytecode request with lambda should fail");
+        } catch (Exception ex) {
+            final ResponseException re = (ResponseException) ex.getCause();
+            assertEquals(ResponseStatusCode.UNAUTHORIZED, re.getResponseStatusCode());
+            assertEquals("Failed to authorize: User not authorized for bytecode requests on [gmodern] using lambdas.", re.getMessage());
+
+            // wait for logger to flush - (don't think there is a way to detect this)
+            stopServer();
+            Thread.sleep(1000);
+
+            assertTrue(recordingAppender.logMatchesAny(AUDIT_LOGGER_NAME, INFO,
+                    "User stephen with address .+? attempted an unauthorized request for bytecode operation: " +
+                            "\\[\\[], \\[V\\(\\), map\\(lambda\\[it.get\\(\\).value\\('name'\\)]\\), count\\(\\)]]"));
+        } finally {
+            cluster.close();
+        }
+    }
+
+    @Test
+    public void shouldKeepAuthorizingBytecodeRequests() {
+        final Cluster cluster = TestClientFactory.build().credentials("stephen", "password").create();
+        final GraphTraversalSource g = AnonymousTraversalSource.traversal().withRemote(
+                DriverRemoteConnection.using(cluster, "gmodern"));
+
+        try {
+            assertEquals(6, (long) g.V().count().next());
+            try {
+                g.V().map(Lambda.function("it.get().value('name')")).count().next();
+                fail("Authorization for bytecode request with lambda should fail");
+            } catch (Exception ex) {
+                final ResponseException re = (ResponseException) ex.getCause();
+                assertEquals(ResponseStatusCode.UNAUTHORIZED, re.getResponseStatusCode());
+                assertEquals("Failed to authorize: User not authorized for bytecode requests on [gmodern] using lambdas.", re.getMessage());
+            }
+            assertEquals(6, (long) g.V().count().next());
+        } finally {
+            cluster.close();
+        }
+    }
+
+    @Test
+    public void shouldAuthorizeStringRequest() throws Exception {
+        final Cluster cluster = TestClientFactory.build().credentials("marko", "rainbow-dash").create();
+        final Client client = cluster.connect();
+
+        try {
+            assertEquals(2, client.submit("1+1").all().get().get(0).getInt());
+            assertEquals(6, client.submit("gclassic.V().count()").all().get().get(0).getInt());
+            assertEquals(6, client.submit("gmodern.V().map{it.get().value('name')}.count()").all().get().get(0).getInt());
+        } finally {
+            cluster.close();
+        }
+    }
+
+    @Test
+    public void shouldFailStringRequestWithGroovyScript() throws Exception {
+        final Cluster cluster = TestClientFactory.build().credentials("stephen", "password").create();
+        final Client client = cluster.connect();
+
+        try {
+            client.submit("1+1").all().get();
+            fail("Authorization without authentication should fail");
+        } catch (Exception ex) {
+            final ResponseException re = (ResponseException) ex.getCause();
+            assertEquals(ResponseStatusCode.UNAUTHORIZED, re.getResponseStatusCode());
+            assertEquals("Failed to authorize: User not authorized for string-based requests.", re.getMessage());
+
+            // wait for logger to flush - (don't think there is a way to detect this)
+            stopServer();
+            Thread.sleep(1000);
+
+            assertTrue(recordingAppender.logMatchesAny(AUDIT_LOGGER_NAME, INFO,
+                    "User stephen with address .+? attempted an unauthorized request for eval operation: 1\\+1"));
+        } finally {
+            cluster.close();
+        }
+    }
+
+    @Test
+    public void shouldFailStringRequestWithGremlinTraversal() {
+        final Cluster cluster = TestClientFactory.build().credentials("stephen", "password").create();
+        final Client client = cluster.connect();
+
+        try {
+            client.submit("gmodern.V().count()").all().get();
+            fail("Authorization without authentication should fail");
+        } catch (Exception ex) {
+            final ResponseException re = (ResponseException) ex.getCause();
+            assertEquals(ResponseStatusCode.UNAUTHORIZED, re.getResponseStatusCode());
+            assertEquals("Failed to authorize: User not authorized for string-based requests.", re.getMessage());
+        } finally {
+            cluster.close();
+        }
+    }
+
+    @Test
+    public void shouldAuthorizeSessionedStringRequest() throws Exception {
+        final Cluster cluster = TestClientFactory.build().credentials("marko", "rainbow-dash").create();
+        final Client client = cluster.connect("session1");
+
+        try {
+            assertEquals(2, client.submit("a = 4; 1+1").all().get().get(0).getInt());
+            assertEquals(10, client.submit("gclassic.V().count().next() + a").all().get().get(0).getInt());
+            assertEquals(6, client.submit("gmodern.V().map{it.get().value('name')}.count()").all().get().get(0).getInt());
+        } finally {
+            cluster.close();
+        }
+    }
+
+    @Test
+    public void shouldFailBytecodeRequestWithAllowAllAuthenticator() {
+        final Cluster cluster = TestClientFactory.build().create();
+        try {
+            final GraphTraversalSource g = AnonymousTraversalSource.traversal().withRemote(
+                    DriverRemoteConnection.using(cluster, "gclassic"));
+            g.V().count().next();
+            fail("Authorization without authentication should fail");
+        } catch (Exception ex) {
+            final ResponseException re = (ResponseException) ex.getCause();
+            assertEquals(ResponseStatusCode.UNAUTHORIZED, re.getResponseStatusCode());
+            assertEquals("Failed to authorize: User not authorized for bytecode requests on [gclassic].", re.getMessage());
+        } finally {
+            cluster.close();
+        }
+    }
+
+    @Test
+    public void shouldFailStringRequestWithAllowAllAuthenticator() {
+        final Cluster cluster = TestClientFactory.build().create();
+        final Client client = cluster.connect();
+
+        try {
+            client.submit("1+1").all().get();
+            fail("Authorization without authentication should fail");
+        } catch (Exception ex) {
+            final ResponseException re = (ResponseException) ex.getCause();
+            assertEquals(ResponseStatusCode.UNAUTHORIZED, re.getResponseStatusCode());
+            assertEquals("Failed to authorize: User not authorized for string-based requests.", re.getMessage());
+        } finally {
+            cluster.close();
+        }
+    }
+
+    @Test
+    public void shouldAuthorizeWithHttpTransport() throws Exception {
+        final CloseableHttpClient httpclient = HttpClients.createDefault();
+        final HttpGet httpget = new HttpGet(TestClientFactory.createURLString("?gremlin=2-1"));
+        httpget.addHeader("Authorization", "Basic " + encoder.encodeToString("marko:rainbow-dash".getBytes()));
+
+        try (final CloseableHttpResponse response = httpclient.execute(httpget)) {
+            assertEquals(200, response.getStatusLine().getStatusCode());
+            assertEquals("application/json", response.getEntity().getContentType().getValue());
+            final String json = EntityUtils.toString(response.getEntity());
+            final JsonNode node = mapper.readTree(json);
+            assertEquals(1, node.get("result").get("data").get(GraphSONTokens.VALUEPROP).get(0).get(GraphSONTokens.VALUEPROP).intValue());
+        }
+    }
+
+    @Test
+    public void shouldFailAuthorizeWithHttpTransport() throws Exception {
+        final CloseableHttpClient httpclient = HttpClients.createDefault();
+        final HttpGet httpget = new HttpGet(TestClientFactory.createURLString("?gremlin=3-1"));
+        httpget.addHeader("Authorization", "Basic " + encoder.encodeToString("stephen:password".getBytes()));
+
+        try (final CloseableHttpResponse response = httpclient.execute(httpget)) {
+            assertEquals(401, response.getStatusLine().getStatusCode());
+        }
+        // wait for logger to flush - (don't think there is a way to detect this)
+        stopServer();
+        Thread.sleep(1000);
+
+        assertTrue(recordingAppender.logMatchesAny(AUDIT_LOGGER_NAME, INFO,
+                "User stephen with address .+? attempted an unauthorized http request: 3-1"));
+    }
+
+    @Test
+    public void shouldKeepAuthorizingWithHttpTransport() throws Exception {
+        HttpGet httpget;
+        final CloseableHttpClient httpclient = HttpClients.createDefault();
+
+        httpget = new HttpGet(TestClientFactory.createURLString("?gremlin=4-1"));
+        httpget.addHeader("Authorization", "Basic " + encoder.encodeToString("marko:rainbow-dash".getBytes()));
+        try (final CloseableHttpResponse response = httpclient.execute(httpget)) {
+            assertEquals(200, response.getStatusLine().getStatusCode());
+            assertEquals("application/json", response.getEntity().getContentType().getValue());
+            final String json = EntityUtils.toString(response.getEntity());
+            final JsonNode node = mapper.readTree(json);
+            assertEquals(3, node.get("result").get("data").get(GraphSONTokens.VALUEPROP).get(0).get(GraphSONTokens.VALUEPROP).intValue());
+        }
+
+        httpget = new HttpGet(TestClientFactory.createURLString("?gremlin=5-1"));
+        httpget.addHeader("Authorization", "Basic " + encoder.encodeToString("stephen:password".getBytes()));
+        try (final CloseableHttpResponse response = httpclient.execute(httpget)) {
+            assertEquals(401, response.getStatusLine().getStatusCode());
+        }
+
+        httpget = new HttpGet(TestClientFactory.createURLString("?gremlin=6-1"));
+        httpget.addHeader("Authorization", "Basic " + encoder.encodeToString("marko:rainbow-dash".getBytes()));
+        try (final CloseableHttpResponse response = httpclient.execute(httpget)) {
+            assertEquals(200, response.getStatusLine().getStatusCode());
+            assertEquals("application/json", response.getEntity().getContentType().getValue());
+            final String json = EntityUtils.toString(response.getEntity());
+            final JsonNode node = mapper.readTree(json);
+            assertEquals(5, node.get("result").get("data").get(GraphSONTokens.VALUEPROP).get(0).get(GraphSONTokens.VALUEPROP).intValue());
+        }
+    }
+
+    @Test
+    public void shouldAuthorizeWithAllowAllAuthenticatorAndHttpTransport() throws Exception {
+        final CloseableHttpClient httpclient = HttpClients.createDefault();
+        final HttpGet httpget = new HttpGet(TestClientFactory.createURLString("?gremlin=7-1"));
+
+        try (final CloseableHttpResponse response = httpclient.execute(httpget)) {
+            assertEquals(200, response.getStatusLine().getStatusCode());
+            assertEquals("application/json", response.getEntity().getContentType().getValue());
+            final String json = EntityUtils.toString(response.getEntity());
+            final JsonNode node = mapper.readTree(json);
+            assertEquals(6, node.get("result").get("data").get(GraphSONTokens.VALUEPROP).get(0).get(GraphSONTokens.VALUEPROP).intValue());
+        }
+    }
+}
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerHttpIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerHttpIntegrateTest.java
index dd1ae15..05cd939 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerHttpIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerHttpIntegrateTest.java
@@ -36,6 +36,7 @@
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClients;
 import org.apache.http.util.EntityUtils;
+import org.apache.tinkerpop.gremlin.server.handler.SaslAndHttpBasicAuthenticationHandler;
 import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONTokens;
 import org.apache.tinkerpop.shaded.jackson.databind.JsonNode;
 import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
@@ -44,12 +45,11 @@
 import java.io.File;
 import java.time.Instant;
 import java.util.Base64;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.core.StringStartsWith.startsWith;
+import static org.hamcrest.core.StringContains.containsString;
 import static org.junit.Assert.assertEquals;
 
 /**
@@ -134,8 +134,9 @@
     private void configureForAuthentication(final Settings settings) {
         final Settings.AuthenticationSettings authSettings = new Settings.AuthenticationSettings();
         authSettings.authenticator = SimpleAuthenticator.class.getName();
+        authSettings.authenticationHandler = SaslAndHttpBasicAuthenticationHandler.class.getName();
 
-        // use a credentials graph with one user in it: stephen/password
+        // use a credentials graph with two users in it: stephen/password and marko/rainbow-dash
         final Map<String,Object> authConfig = new HashMap<>();
         authConfig.put(SimpleAuthenticator.CONFIG_CREDENTIALS_DB, "conf/tinkergraph-credentials.properties");
 
@@ -148,9 +149,9 @@
         authSettings.authenticator = SimpleAuthenticator.class.getName();
 
         //Add basic auth handler to make sure the reflection code path works.
-        authSettings.authenticationHandler = HttpBasicAuthenticationHandler.class.getName();
+        authSettings.authenticationHandler = SaslAndHttpBasicAuthenticationHandler.class.getName();
 
-        // use a credentials graph with one user in it: stephen/password
+        // use a credentials graph with two users in it: stephen/password and marko/rainbow-dash
         final Map<String,Object> authConfig = new HashMap<>();
         authConfig.put(SimpleAuthenticator.CONFIG_CREDENTIALS_DB, "conf/tinkergraph-credentials.properties");
 
@@ -234,7 +235,7 @@
         final HttpPost httppost = new HttpPost(TestClientFactory.createURLString());
         httppost.addHeader("Content-Type", "application/json");
         httppost.addHeader("Authorization", "Basic: not-base-64-encoded");
-        httppost.setEntity(new StringEntity("{\"gremlin\":\"1-1\"}", Consts.UTF_8));
+        httppost.setEntity(new StringEntity("{\"gremlin\":\"2-1\"}", Consts.UTF_8));
 
         try (final CloseableHttpResponse response = httpclient.execute(httppost)) {
             assertEquals(401, response.getStatusLine().getStatusCode());
@@ -773,7 +774,7 @@
             final JsonNode node = mapper.readTree(json);
             assertEquals("java.lang.ArithmeticException", node.get(Tokens.STATUS_ATTRIBUTE_EXCEPTIONS).get(0).asText());
             assertEquals(1, node.get(Tokens.STATUS_ATTRIBUTE_EXCEPTIONS).size());
-            assertThat(node.get(Tokens.STATUS_ATTRIBUTE_STACK_TRACE).asText(), startsWith("java.lang.ArithmeticException: Division by zero\n\tat java.math.BigDecimal.divide(BigDecimal.java"));
+            assertThat(node.get(Tokens.STATUS_ATTRIBUTE_STACK_TRACE).asText(), containsString("Division by zero"));
         }
     }
 
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java
index 8a63694..7d9983f 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java
@@ -18,8 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.server;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.commons.lang3.exception.ExceptionUtils;
 import org.apache.log4j.Level;
 import org.apache.log4j.Logger;
@@ -34,19 +34,17 @@
 import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
 import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection;
-import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteTraversalSideEffects;
 import org.apache.tinkerpop.gremlin.driver.ser.Serializers;
 import org.apache.tinkerpop.gremlin.driver.simple.SimpleClient;
 import org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine;
 import org.apache.tinkerpop.gremlin.groovy.jsr223.GroovyCompilerGremlinPlugin;
 import org.apache.tinkerpop.gremlin.groovy.jsr223.customizer.SimpleSandboxExtension;
 import org.apache.tinkerpop.gremlin.jsr223.ScriptFileGremlinPlugin;
+import org.apache.tinkerpop.gremlin.server.handler.UnifiedHandler;
 import org.apache.tinkerpop.gremlin.structure.RemoteGraph;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.BulkSet;
 import org.apache.tinkerpop.gremlin.server.handler.OpSelectorHandler;
 import org.apache.tinkerpop.gremlin.server.op.AbstractEvalOpProcessor;
 import org.apache.tinkerpop.gremlin.server.op.standard.StandardOpProcessor;
@@ -60,15 +58,15 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+
 import org.slf4j.LoggerFactory;
 
-import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
-import java.util.UUID;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -78,7 +76,7 @@
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
 
-import static org.apache.tinkerpop.gremlin.driver.Tokens.ARGS_SCRIPT_EVAL_TIMEOUT;
+import static org.apache.tinkerpop.gremlin.driver.Tokens.ARGS_EVAL_TIMEOUT;
 import static org.apache.tinkerpop.gremlin.groovy.jsr223.GroovyCompilerGremlinPlugin.Compilation.COMPILE_STATIC;
 import static org.apache.tinkerpop.gremlin.process.remote.RemoteConnection.GREMLIN_REMOTE;
 import static org.apache.tinkerpop.gremlin.process.remote.RemoteConnection.GREMLIN_REMOTE_CONNECTION_CLASS;
@@ -86,6 +84,7 @@
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.AllOf.allOf;
 import static org.hamcrest.core.IsInstanceOf.instanceOf;
 import static org.hamcrest.core.IsNot.not;
 import static org.hamcrest.core.StringStartsWith.startsWith;
@@ -93,12 +92,15 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeThat;
+
 /**
  * Integration tests for server-side settings and processing.
  *
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
 public class GremlinServerIntegrateTest extends AbstractGremlinServerIntegrationTest {
+
     private Level previousLogLevel;
     private static final org.slf4j.Logger logger = LoggerFactory.getLogger(GremlinServerIntegrateTest.class);
 
@@ -120,9 +122,11 @@
 
         if (name.getMethodName().equals("shouldPingChannelIfClientDies") ||
                 name.getMethodName().equals("shouldCloseChannelIfClientDoesntRespond")) {
-            final org.apache.log4j.Logger webSocketClientHandlerLogger = org.apache.log4j.Logger.getLogger(OpSelectorHandler.class);
-            previousLogLevel = webSocketClientHandlerLogger.getLevel();
-            webSocketClientHandlerLogger.setLevel(Level.INFO);
+            final org.apache.log4j.Logger opSelectorHandlerLogger = org.apache.log4j.Logger.getLogger(OpSelectorHandler.class);
+            final org.apache.log4j.Logger unifiedHandlerLogger = org.apache.log4j.Logger.getLogger(UnifiedHandler.class);
+            previousLogLevel = opSelectorHandlerLogger.getLevel();
+            opSelectorHandlerLogger.setLevel(Level.INFO);
+            unifiedHandlerLogger.setLevel(Level.INFO);
         }
 
         rootLogger.addAppender(recordingAppender);
@@ -134,8 +138,10 @@
 
         if (name.getMethodName().equals("shouldPingChannelIfClientDies")||
                 name.getMethodName().equals("shouldCloseChannelIfClientDoesntRespond")) {
-            final org.apache.log4j.Logger webSocketClientHandlerLogger = org.apache.log4j.Logger.getLogger(OpSelectorHandler.class);
-            webSocketClientHandlerLogger.setLevel(previousLogLevel);
+            final org.apache.log4j.Logger opSelectorHandlerLogger = org.apache.log4j.Logger.getLogger(OpSelectorHandler.class);
+            opSelectorHandlerLogger.setLevel(previousLogLevel);
+            final org.apache.log4j.Logger unifiedHandlerLogger = org.apache.log4j.Logger.getLogger(UnifiedHandler.class);
+            unifiedHandlerLogger.setLevel(previousLogLevel);
         }
 
         rootLogger.removeAppender(recordingAppender);
@@ -150,6 +156,8 @@
         switch (nameOfTest) {
             case "shouldProvideBetterExceptionForMethodCodeTooLarge":
                 settings.maxContentLength = 4096000;
+
+                // OpProcessor setting
                 final Settings.ProcessorSettings processorSettingsBig = new Settings.ProcessorSettings();
                 processorSettingsBig.className = StandardOpProcessor.class.getName();
                 processorSettingsBig.config = new HashMap<String,Object>() {{
@@ -157,6 +165,9 @@
                 }};
                 settings.processors.clear();
                 settings.processors.add(processorSettingsBig);
+
+                // Unified setting
+                settings.maxParameters = Integer.MAX_VALUE;
                 break;
             case "shouldRespectHighWaterMarkSettingAndSucceed":
                 settings.writeBufferHighWaterMark = 64;
@@ -169,6 +180,7 @@
                 settings.maxContentLength = 1024;
                 break;
             case "shouldBatchResultsByTwos":
+            case "shouldBatchResultsByTwosToDriver":
                 settings.resultIterationBatchSize = 2;
                 break;
             case "shouldUseSimpleSandbox":
@@ -187,6 +199,7 @@
                 settings.scriptEngines.get("gremlin-groovy").config = getScriptEngineConfForBaseScript();
                 break;
             case "shouldReturnInvalidRequestArgsWhenBindingCountExceedsAllowable":
+                // OpProcessor settings
                 final Settings.ProcessorSettings processorSettingsSmall = new Settings.ProcessorSettings();
                 processorSettingsSmall.className = StandardOpProcessor.class.getName();
                 processorSettingsSmall.config = new HashMap<String,Object>() {{
@@ -194,19 +207,23 @@
                 }};
                 settings.processors.clear();
                 settings.processors.add(processorSettingsSmall);
+
+                // Unified settings
+                settings.maxParameters = 1;
                 break;
             case "shouldTimeOutRemoteTraversal":
                 settings.evaluationTimeout = 500;
                 break;
-            case "shouldTimeOutRemoteTraversalUsingDeprecatedConfiguration":
-                settings.scriptEvaluationTimeout = 500;
-                break;
             case "shouldPingChannelIfClientDies":
                 settings.keepAliveInterval = 1000;
                 break;
             case "shouldCloseChannelIfClientDoesntRespond":
                 settings.idleConnectionTimeout = 1000;
                 break;
+            case "shouldBlowTheWorkQueueSize":
+                settings.gremlinPool = 1;
+                settings.maxWorkQueueSize = 1;
+                break;
             default:
                 break;
         }
@@ -242,6 +259,41 @@
     }
 
     @Test
+    public void shouldBlowTheWorkQueueSize() throws Exception {
+        final Cluster cluster = TestClientFactory.open();
+        final Client client = cluster.connect();
+
+        // maxWorkQueueSize=1 && gremlinPool=1
+        // we should be able to do one request at a time serially
+        assertEquals("test1", client.submit("'test1'").all().get().get(0).getString());
+        assertEquals("test2", client.submit("'test2'").all().get().get(0).getString());
+        assertEquals("test3", client.submit("'test3'").all().get().get(0).getString());
+
+        final AtomicBoolean errorTriggered = new AtomicBoolean();
+        final ResultSet r1 = client.submitAsync("Thread.sleep(1000);'test4'").get();
+
+        final List<CompletableFuture<List<Result>>> blockers = new ArrayList<>();
+        for (int ix = 0; ix < 512 && !errorTriggered.get(); ix++) {
+            blockers.add(client.submit("'test'").all().exceptionally(t -> {
+                final ResponseException re = (ResponseException) t.getCause();
+                errorTriggered.compareAndSet(false, ResponseStatusCode.TOO_MANY_REQUESTS == re.getResponseStatusCode());
+                return null;
+            }));
+        }
+
+        assertThat(errorTriggered.get(), is(true));
+
+        // wait for the blockage to clear for sure
+        assertEquals("test4", r1.all().get().get(0).getString());
+        blockers.forEach(CompletableFuture::join);
+
+        // should be accepting test6 now
+        assertEquals("test6", client.submit("'test6'").all().get().get(0).getString());
+
+        cluster.close();
+    }
+
+    @Test
     public void shouldScriptEvaluationErrorForRemoteTraversal() throws Exception {
         final GraphTraversalSource g = traversal().withRemote(conf);
 
@@ -252,7 +304,7 @@
         } catch (Exception ex) {
             final Throwable t = ex.getCause();
             assertThat(t, instanceOf(ResponseException.class));
-            assertEquals(ResponseStatusCode.SERVER_ERROR_SCRIPT_EVALUATION, ((ResponseException) t).getResponseStatusCode());
+            assertEquals(ResponseStatusCode.SERVER_ERROR_EVALUATION, ((ResponseException) t).getResponseStatusCode());
         }
 
         // make a graph with a cycle in it to force a long run traversal
@@ -330,40 +382,12 @@
     }
 
     @Test
-    public void shouldTimeOutRemoteTraversalUsingDeprecatedConfiguration() throws Exception {
-        final GraphTraversalSource g = traversal().withRemote(conf);
-
-        try {
-            // tests sleeping thread
-            g.inject(1).sideEffect(Lambda.consumer("Thread.sleep(10000)")).iterate();
-            fail("This traversal should have timed out");
-        } catch (Exception ex) {
-            final Throwable t = ex.getCause();
-            assertThat(t, instanceOf(ResponseException.class));
-            assertEquals(ResponseStatusCode.SERVER_ERROR_TIMEOUT, ((ResponseException) t).getResponseStatusCode());
-        }
-
-        // make a graph with a cycle in it to force a long run traversal
-        graphGetter.get().traversal().addV("person").as("p").addE("self").to("p").iterate();
-
-        try {
-            // tests an "unending" traversal
-            g.V().repeat(__.out()).until(__.outE().count().is(0)).iterate();
-            fail("This traversal should have timed out");
-        } catch (Exception ex) {
-            final Throwable t = ex.getCause();
-            assertThat(t, instanceOf(ResponseException.class));
-            assertEquals(ResponseStatusCode.SERVER_ERROR_TIMEOUT, ((ResponseException) t).getResponseStatusCode());
-        }
-    }
-
-    @Test
     public void shouldTimeOutRemoteTraversalWithPerRequestOption() {
         final GraphTraversalSource g = traversal().withRemote(conf);
 
         try {
             // tests sleeping thread
-            g.with(ARGS_SCRIPT_EVAL_TIMEOUT, 500L).inject(1).sideEffect(Lambda.consumer("Thread.sleep(10000)")).iterate();
+            g.with(ARGS_EVAL_TIMEOUT, 500L).inject(1).sideEffect(Lambda.consumer("Thread.sleep(10000)")).iterate();
             fail("This traversal should have timed out");
         } catch (Exception ex) {
             final Throwable t = ex.getCause();
@@ -376,7 +400,7 @@
 
         try {
             // tests an "unending" traversal
-            g.with(ARGS_SCRIPT_EVAL_TIMEOUT, 500L).V().repeat(__.out()).until(__.outE().count().is(0)).iterate();
+            g.with(ARGS_EVAL_TIMEOUT, 500L).V().repeat(__.out()).until(__.outE().count().is(0)).iterate();
             fail("This traversal should have timed out");
         } catch (Exception ex) {
             final Throwable t = ex.getCause();
@@ -387,6 +411,9 @@
 
     @Test
     public void shouldProduceProperExceptionOnTimeout() throws Exception {
+        // this test will not work quite right on UnifiedChannelizer
+        assumeThat("Must use OpProcessor", isUsingUnifiedChannelizer(), is(false));
+
         final Cluster cluster = TestClientFactory.open();
         final Client client = cluster.connect(name.getMethodName());
 
@@ -688,6 +715,9 @@
     @Test
     @SuppressWarnings("unchecked")
     public void shouldBatchResultsByTwos() throws Exception {
+        // this test will not work quite right on UnifiedChannelizer, but seems to only be a problem in Travis
+        assumeThat("Must use OpProcessor", isUsingUnifiedChannelizer(), is(false));
+
         try (SimpleClient client = TestClientFactory.createWebSocketClient()) {
             final RequestMessage request = RequestMessage.build(Tokens.OPS_EVAL)
                     .addArg(Tokens.ARGS_GREMLIN, "[0,1,2,3,4,5,6,7,8,9]").create();
@@ -707,6 +737,21 @@
         }
     }
 
+//    @Test
+//    public void shouldBatchResultsByTwosWithDriver() throws Exception {
+//        final Cluster cluster = TestClientFactory.build().create();
+//        final Client client = cluster.connect();
+//
+//        try {
+//            final List<Result> results = client.submit("[0,1,2,3,4,5,6,7,8,9]").all().join();
+//            for (int ix = 0; ix < results.size(); ix++) {
+//                assertEquals(ix, results.get(ix).getInt());
+//            }
+//        } finally {
+//            cluster.close();
+//        }
+//    }
+
     @Test
     @SuppressWarnings("unchecked")
     public void shouldBatchResultsByOnesByOverridingFromClientSide() throws Exception {
@@ -735,23 +780,7 @@
     public void shouldReceiveFailureTimeOutOnScriptEval() throws Exception {
         try (SimpleClient client = TestClientFactory.createWebSocketClient()){
             final List<ResponseMessage> responses = client.submit("Thread.sleep(3000);'some-stuff-that-should not return'");
-            assertThat(responses.get(0).getStatus().getMessage(), startsWith("Evaluation exceeded the configured 'evaluationTimeout' threshold of 1000 ms"));
-
-            // validate that we can still send messages to the server
-            assertEquals(2, ((List<Integer>) client.submit("1+1").get(0).getResult().getData()).get(0).intValue());
-        }
-    }
-
-    @Test
-    @SuppressWarnings("unchecked")
-    public void shouldReceiveFailureTimeOutOnScriptEvalUsingOverride() throws Exception {
-        try (SimpleClient client = TestClientFactory.createWebSocketClient()) {
-            final RequestMessage msg = RequestMessage.build("eval")
-                    .addArg(ARGS_SCRIPT_EVAL_TIMEOUT, 100L)
-                    .addArg(Tokens.ARGS_GREMLIN, "Thread.sleep(3000);'some-stuff-that-should not return'")
-                    .create();
-            final List<ResponseMessage> responses = client.submit(msg);
-            assertThat(responses.get(0).getStatus().getMessage(), startsWith("Evaluation exceeded the configured 'evaluationTimeout' threshold of 100 ms"));
+            assertThat(responses.get(0).getStatus().getMessage(), allOf(startsWith("Evaluation exceeded"), containsString("1000 ms")));
 
             // validate that we can still send messages to the server
             assertEquals(2, ((List<Integer>) client.submit("1+1").get(0).getResult().getData()).get(0).intValue());
@@ -767,7 +796,7 @@
                     .addArg(Tokens.ARGS_GREMLIN, "Thread.sleep(3000);'some-stuff-that-should not return'")
                     .create();
             final List<ResponseMessage> responses = client.submit(msg);
-            assertThat(responses.get(0).getStatus().getMessage(), startsWith("Evaluation exceeded the configured 'evaluationTimeout' threshold of 100 ms"));
+            assertThat(responses.get(0).getStatus().getMessage(), allOf(startsWith("Evaluation exceeded"), containsString("100 ms")));
 
             // validate that we can still send messages to the server
             assertEquals(2, ((List<Integer>) client.submit("1+1").get(0).getResult().getData()).get(0).intValue());
@@ -969,7 +998,7 @@
             final RequestMessage request = RequestMessage.build(Tokens.OPS_EVAL)
                     .addArg(Tokens.ARGS_GREMLIN, "new String().doNothingAtAllBecauseThis is a syntax error").create();
             final List<ResponseMessage> responses = client.submit(request);
-            assertEquals(ResponseStatusCode.SERVER_ERROR_SCRIPT_EVALUATION, responses.get(0).getStatus().getCode());
+            assertEquals(ResponseStatusCode.SERVER_ERROR_EVALUATION, responses.get(0).getStatus().getCode());
             assertEquals(1, responses.size());
         }
     }
@@ -983,178 +1012,6 @@
     }
 
     @Test
-    public void shouldGetSideEffectKeysAndStatusUsingWithRemote() throws Exception {
-        final GraphTraversalSource g = traversal().withRemote(conf);
-        g.addV("person").property("age", 20).iterate();
-        g.addV("person").property("age", 10).iterate();
-        final GraphTraversal traversal = g.V().aggregate("a").aggregate("b");
-        traversal.iterate();
-        final DriverRemoteTraversalSideEffects se = (DriverRemoteTraversalSideEffects) traversal.asAdmin().getSideEffects();
-        assertThat(se.statusAttributes().containsKey(Tokens.ARGS_HOST), is(true));
-
-        // Get keys
-        final Set<String> sideEffectKeys = se.keys();
-        assertEquals(2, sideEffectKeys.size());
-
-        // Get side effects
-        final BulkSet aSideEffects = se.get("a");
-        assertThat(aSideEffects.isEmpty(), is(false));
-        final BulkSet bSideEffects = se.get("b");
-        assertThat(bSideEffects.isEmpty(), is(false));
-
-        // Should get local keys/side effects after close
-        se.close();
-
-        final Set<String> localSideEffectKeys = se.keys();
-        assertEquals(2, localSideEffectKeys.size());
-
-        final BulkSet localASideEffects = se.get("a");
-        assertThat(localASideEffects.isEmpty(), is(false));
-
-        final BulkSet localBSideEffects = se.get("b");
-        assertThat(localBSideEffects.isEmpty(), is(false));
-
-        final GraphTraversal gdotv = g.V();
-        gdotv.toList();
-        final DriverRemoteTraversalSideEffects gdotvSe = (DriverRemoteTraversalSideEffects) gdotv.asAdmin().getSideEffects();
-        assertThat(gdotvSe.statusAttributes().containsKey(Tokens.ARGS_HOST), is(true));
-    }
-
-    @Test
-    public void shouldCloseSideEffectsUsingWithRemote() throws Exception {
-        final GraphTraversalSource g = traversal().withRemote(conf);
-        g.addV("person").property("age", 20).iterate();
-        g.addV("person").property("age", 10).iterate();
-        final GraphTraversal traversal = g.V().aggregate("a").aggregate("b");
-        traversal.iterate();
-        final DriverRemoteTraversalSideEffects se = (DriverRemoteTraversalSideEffects) traversal.asAdmin().getSideEffects();
-        final BulkSet sideEffects = se.get("a");
-        assertThat(sideEffects.isEmpty(), is(false));
-        se.close();
-
-        // Can't get new side effects after close
-        try {
-            se.get("b");
-            fail("The traversal is closed");
-        } catch (Exception ex) {
-            assertThat(ex, instanceOf(IllegalStateException.class));
-            assertEquals("Traversal has been closed - no new side-effects can be retrieved", ex.getMessage());
-        }
-
-        // Earlier keys should be cached locally
-        final Set<String> localSideEffectKeys = se.keys();
-        assertEquals(2, localSideEffectKeys.size());
-        final BulkSet localSideEffects = se.get("a");
-        assertThat(localSideEffects.isEmpty(), is(false));
-
-        // Try to get side effect from server
-        final Cluster cluster = TestClientFactory.open();
-        final Client client = cluster.connect();
-        final Field field = DriverRemoteTraversalSideEffects.class.getDeclaredField("serverSideEffect");
-        field.setAccessible(true);
-        final UUID serverSideEffectId = (UUID) field.get(se);
-        final Map<String, String> aliases = new HashMap<>();
-        aliases.put("g", "g");
-        final RequestMessage msg = RequestMessage.build(Tokens.OPS_GATHER)
-                .addArg(Tokens.ARGS_SIDE_EFFECT, serverSideEffectId)
-                .addArg(Tokens.ARGS_SIDE_EFFECT_KEY, "b")
-                .addArg(Tokens.ARGS_ALIASES, aliases)
-                .processor("traversal").create();
-        boolean error;
-        try {
-            client.submitAsync(msg).get().one();
-            error = false;
-        } catch (Exception ex) {
-            error = true;
-        }
-        assertThat(error, is(true));
-    }
-
-    @Test
-    public void shouldBlockWhenGettingSideEffectKeysUsingWithRemote() throws Exception {
-        final GraphTraversalSource g = traversal().withRemote(conf);
-        g.addV("person").property("age", 20).iterate();
-        g.addV("person").property("age", 10).iterate();
-        final GraphTraversal traversal = g.V().aggregate("a")
-                .sideEffect(Lambda.consumer("{Thread.sleep(3000)}"))
-                .aggregate("b");
-
-        // force strategy application - if this doesn't happen then getSideEffects() returns DefaultTraversalSideEffects
-        traversal.hasNext();
-
-        // start a separate thread to iterate
-        final Thread t = new Thread(traversal::iterate);
-        t.start();
-
-        // blocks here until traversal iteration is complete
-        final DriverRemoteTraversalSideEffects se = (DriverRemoteTraversalSideEffects) traversal.asAdmin().getSideEffects();
-
-        // Get keys
-        final Set<String> sideEffectKeys = se.keys();
-        assertEquals(2, sideEffectKeys.size());
-
-        // Get side effects
-        final BulkSet aSideEffects = se.get("a");
-        assertThat(aSideEffects.isEmpty(), is(false));
-        final BulkSet bSideEffects = se.get("b");
-        assertThat(bSideEffects.isEmpty(), is(false));
-
-        // Should get local keys/side effects after close
-        se.close();
-
-        final Set<String> localSideEffectKeys = se.keys();
-        assertEquals(2, localSideEffectKeys.size());
-
-        final BulkSet localASideEffects = se.get("a");
-        assertThat(localASideEffects.isEmpty(), is(false));
-
-        final BulkSet localBSideEffects = se.get("b");
-        assertThat(localBSideEffects.isEmpty(), is(false));
-    }
-
-    @Test
-    public void shouldBlockWhenGettingSideEffectValuesUsingWithRemote() throws Exception {
-        final GraphTraversalSource g = traversal().withRemote(conf);
-        g.addV("person").property("age", 20).iterate();
-        g.addV("person").property("age", 10).iterate();
-        final GraphTraversal traversal = g.V().aggregate("a")
-                .sideEffect(Lambda.consumer("{Thread.sleep(3000)}"))
-                .aggregate("b");
-
-        // force strategy application - if this doesn't happen then getSideEffects() returns DefaultTraversalSideEffects
-        traversal.hasNext();
-
-        // start a separate thread to iterate
-        final Thread t = new Thread(traversal::iterate);
-        t.start();
-
-        // blocks here until traversal iteration is complete
-        final DriverRemoteTraversalSideEffects se = (DriverRemoteTraversalSideEffects) traversal.asAdmin().getSideEffects();
-
-        // Get side effects
-        final BulkSet aSideEffects = se.get("a");
-        assertThat(aSideEffects.isEmpty(), is(false));
-        final BulkSet bSideEffects = se.get("b");
-        assertThat(bSideEffects.isEmpty(), is(false));
-
-        // Get keys
-        final Set<String> sideEffectKeys = se.keys();
-        assertEquals(2, sideEffectKeys.size());
-
-        // Should get local keys/side effects after close
-        se.close();
-
-        final Set<String> localSideEffectKeys = se.keys();
-        assertEquals(2, localSideEffectKeys.size());
-
-        final BulkSet localASideEffects = se.get("a");
-        assertThat(localASideEffects.isEmpty(), is(false));
-
-        final BulkSet localBSideEffects = se.get("b");
-        assertThat(localBSideEffects.isEmpty(), is(false));
-    }
-
-    @Test
     public void shouldDoNonBlockingPromiseWithRemote() throws Exception {
         final GraphTraversalSource g = traversal().withRemote(conf);
         g.addV("person").property("age", 20).promise(Traversal::iterate).join();
@@ -1201,4 +1058,20 @@
             assertThat(ex.getMessage(), containsString("The Gremlin statement that was submitted exceeds the maximum compilation size allowed by the JVM"));
         }
     }
+
+    @Test
+    public void shouldGenerateTemporaryErrorResponseStatusCode() throws Exception {
+        final Cluster cluster = TestClientFactory.build().create();
+        final Client client = cluster.connect();
+
+        try {
+            client.submit("g.addV('person').sideEffect{throw new org.apache.tinkerpop.gremlin.server.util.DefaultTemporaryException('try again!')}").all().get();
+            fail("Should have tanked since we threw an exception out manually");
+        } catch (Exception ex) {
+            final Throwable t = ex.getCause();
+            assertThat(t, instanceOf(ResponseException.class));
+            assertEquals("try again!", t.getMessage());
+            assertEquals(ResponseStatusCode.SERVER_ERROR_TEMPORARY, ((ResponseException) t).getResponseStatusCode());
+        }
+    }
 }
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSessionIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSessionIntegrateTest.java
index ddf39d3..48919b5 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSessionIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSessionIntegrateTest.java
@@ -23,6 +23,7 @@
 import org.apache.log4j.Logger;
 import org.apache.tinkerpop.gremlin.driver.Client;
 import org.apache.tinkerpop.gremlin.driver.Cluster;
+import org.apache.tinkerpop.gremlin.driver.RequestOptions;
 import org.apache.tinkerpop.gremlin.driver.Result;
 import org.apache.tinkerpop.gremlin.driver.ResultSet;
 import org.apache.tinkerpop.gremlin.driver.Tokens;
@@ -31,6 +32,8 @@
 import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
 import org.apache.tinkerpop.gremlin.driver.simple.SimpleClient;
+import org.apache.tinkerpop.gremlin.server.channel.UnifiedChannelizer;
+import org.apache.tinkerpop.gremlin.server.op.session.Session;
 import org.apache.tinkerpop.gremlin.server.op.session.SessionOpProcessor;
 import org.apache.tinkerpop.gremlin.util.Log4jRecordingAppender;
 import org.junit.After;
@@ -43,16 +46,18 @@
 import java.util.List;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.IntStream;
 
 import static org.hamcrest.CoreMatchers.instanceOf;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.core.IsCollectionContaining.hasItem;
+import static org.hamcrest.core.IsIterableContaining.hasItem;
 import static org.hamcrest.core.StringStartsWith.startsWith;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeThat;
 
 /**
  * @author Stephen Mallette (http://stephen.genoprime.com)
@@ -70,9 +75,9 @@
         switch (nameOfTest) {
             case "shouldCloseSessionOnceOnRequest":
             case "shouldHaveTheSessionTimeout":
-            case "shouldBlockAdditionalRequestsDuringClose":
-            case "shouldBlockAdditionalRequestsDuringForceClose":
-                Logger.getRootLogger().setLevel(Level.INFO);
+            case "shouldCloseSessionOnClientClose":
+                final org.apache.log4j.Logger sessionLogger = org.apache.log4j.Logger.getLogger(Session.class);
+                sessionLogger.setLevel(Level.DEBUG);
                 break;
         }
         rootLogger.addAppender(recordingAppender);
@@ -80,9 +85,9 @@
 
     @After
     public void teardownForEachTest() {
-        final Logger rootLogger = Logger.getRootLogger();
-        rootLogger.setLevel(originalLevel);
-        rootLogger.removeAppender(recordingAppender);
+        final org.apache.log4j.Logger sessionLogger = org.apache.log4j.Logger.getLogger(Session.class);
+        sessionLogger.setLevel(originalLevel);
+        sessionLogger.removeAppender(recordingAppender);
     }
 
     /**
@@ -95,32 +100,56 @@
             case "shouldHaveTheSessionTimeout":
             case "shouldCloseSessionOnceOnRequest":
                 settings.processors.clear();
+
+                // OpProcessor setting
                 final Settings.ProcessorSettings processorSettings = new Settings.ProcessorSettings();
                 processorSettings.className = SessionOpProcessor.class.getCanonicalName();
                 processorSettings.config = new HashMap<>();
                 processorSettings.config.put(SessionOpProcessor.CONFIG_SESSION_TIMEOUT, 3000L);
                 settings.processors.add(processorSettings);
+
+                // Unified setting
+                settings.sessionLifetimeTimeout = 3000L;
                 break;
-            case "shouldBlockAdditionalRequestsDuringClose":
-            case "shouldBlockAdditionalRequestsDuringForceClose":
+            case "shouldCloseSessionOnClientClose":
+            case "shouldCloseSessionOnClientCloseWithStateMaintainedBetweenExceptions":
                 clearNeo4j(settings);
                 break;
             case "shouldEnsureSessionBindingsAreThreadSafe":
                 settings.threadPoolWorker = 2;
                 break;
+            case "shouldUseGlobalFunctionCache":
+                // OpProcessor settings are good by default
+                // UnifiedHandler settings
+                settings.useCommonEngineForSessions = false;
+                settings.useGlobalFunctionCacheForSessions = true;
+
+                break;
             case "shouldNotUseGlobalFunctionCache":
                 settings.processors.clear();
+
+                // OpProcessor settings
                 final Settings.ProcessorSettings processorSettingsForDisableFunctionCache = new Settings.ProcessorSettings();
                 processorSettingsForDisableFunctionCache.className = SessionOpProcessor.class.getCanonicalName();
                 processorSettingsForDisableFunctionCache.config = new HashMap<>();
                 processorSettingsForDisableFunctionCache.config.put(SessionOpProcessor.CONFIG_GLOBAL_FUNCTION_CACHE_ENABLED, false);
                 settings.processors.add(processorSettingsForDisableFunctionCache);
+
+                // UnifiedHandler settings
+                settings.useCommonEngineForSessions = false;
+                settings.useGlobalFunctionCacheForSessions = false;
+
                 break;
             case "shouldExecuteInSessionAndSessionlessWithoutOpeningTransactionWithSingleClient":
             case "shouldExecuteInSessionWithTransactionManagement":
             case "shouldRollbackOnEvalExceptionForManagedTransaction":
+            case "shouldNotExecuteQueuedRequestsIfOneInFrontOfItFails":
                 clearNeo4j(settings);
                 break;
+            case "shouldBlowTheSessionQueueSize":
+                clearNeo4j(settings);
+                settings.maxSessionTaskQueueSize = 1;
+                break;
         }
 
         return settings;
@@ -132,13 +161,205 @@
     }
 
     @Test
-    public void shouldUseGlobalFunctionCache() throws Exception {
+    public void shouldBlowTheSessionQueueSize() throws Exception {
+        assumeNeo4jIsPresent();
+        assumeThat(isUsingUnifiedChannelizer(), is(true));
+
         final Cluster cluster = TestClientFactory.open();
-        final Client client = cluster.connect(name.getMethodName());
+        final Client session = cluster.connect(name.getMethodName());
+
+        // maxSessionQueueSize=1
+        // we should be able to do one request at a time serially
+        assertEquals("test1", session.submit("'test1'").all().get().get(0).getString());
+        assertEquals("test2", session.submit("'test2'").all().get().get(0).getString());
+        assertEquals("test3", session.submit("'test3'").all().get().get(0).getString());
+
+        final AtomicBoolean errorTriggered = new AtomicBoolean();
+        final ResultSet r1 = session.submitAsync("Thread.sleep(1000);'test4'").get();
+
+        final List<CompletableFuture<List<Result>>> blockers = new ArrayList<>();
+        for (int ix = 0; ix < 512 && !errorTriggered.get(); ix++) {
+            blockers.add(session.submit("'test'").all().exceptionally(t -> {
+                final ResponseException re = (ResponseException) t.getCause();
+                errorTriggered.compareAndSet(false, ResponseStatusCode.TOO_MANY_REQUESTS == re.getResponseStatusCode());
+                return null;
+            }));
+
+            // low resource environments like travis might need a break
+            if (ix % 32 == 0) Thread.sleep(500);
+        }
+
+        // wait for the blockage to clear for sure
+        assertEquals("test4", r1.all().get().get(0).getString());
+        blockers.forEach(CompletableFuture::join);
+
+        assertThat(errorTriggered.get(), is(true));
+
+        // should be accepting test6 now
+        assertEquals("test6", session.submit("'test6'").all().get().get(0).getString());
+
+        session.close();
+        cluster.close();
+    }
+
+    @Test
+    public void shouldNotExecuteQueuedRequestsIfOneInFrontOfItFails() throws Exception {
+        assumeNeo4jIsPresent();
+        assumeThat(isUsingUnifiedChannelizer(), is(true));
+
+        final Cluster cluster = TestClientFactory.open();
+        final Client session = cluster.connect(name.getMethodName());
+        final List<CompletableFuture<ResultSet>> futuresAfterFailure = new ArrayList<>();
+
+        // short, sweet and successful - but will rollback after close
+        final CompletableFuture<List<Result>> first = session.submit("g.addV('person').iterate();1").all();
+        assertEquals(1, first.get().get(0).getInt());
+
+        // leave enough time for the results to queue behind this
+        final int followOnRequestCount = 8;
+        final CompletableFuture<ResultSet> second = session.submitAsync("g.addV('person').sideEffect{Thread.sleep(60000)}");
+
+        // these requests will queue
+        for (int ix = 0; ix < followOnRequestCount; ix ++) {
+            futuresAfterFailure.add(session.submitAsync("g.addV('software')"));
+        }
+
+        // close the session which will interrupt "second" request and flush the queue of requests behind it
+        session.close();
 
         try {
-            assertEquals(3, client.submit("def addItUp(x,y){x+y};addItUp(1,2)").all().get().get(0).getInt());
-            assertEquals(3, client.submit("addItUp(1,2)").all().get().get(0).getInt());
+            second.join().all().join();
+            fail("should have been interrupted by channel close");
+        } catch (Exception ex) {
+            assertEquals("Connection to server is no longer active", ex.getCause().getMessage());
+        }
+
+        final AtomicInteger fails = new AtomicInteger(0);
+        futuresAfterFailure.forEach(f -> {
+            try {
+                f.join().all().join();
+                fail("should have been interrupted by channel close");
+            } catch (Exception ex) {
+                assertEquals("Connection to server is no longer active", ex.getCause().getMessage());
+                fails.incrementAndGet();
+            }
+        });
+
+        // all are failures
+        assertEquals(followOnRequestCount, fails.get());
+
+        // validate the rollback
+        final Client client = cluster.connect();
+        assertEquals(0, client.submit("g.V().count()").all().get().get(0).getInt());
+        cluster.close();
+    }
+
+    @Test
+    public void shouldCloseSessionOnClientClose() throws Exception {
+        assumeNeo4jIsPresent();
+
+        final Cluster cluster1 = TestClientFactory.open();
+        final Client client1 = cluster1.connect(name.getMethodName());
+        client1.submit("x = 1").all().join();
+        client1.submit("graph.addVertex()").all().join();
+        client1.close();
+        cluster1.close();
+
+        // the following session close log message is no longer relevant as
+        if (isUsingUnifiedChannelizer()) {
+            assertThat(((UnifiedChannelizer) server.getChannelizer()).getUnifiedHandler().isActiveSession(name.getMethodName()), is(false));
+        } else {
+            assertThat(recordingAppender.getMessages(), hasItem("DEBUG - Skipped attempt to close open graph transactions on shouldCloseSessionOnClientClose - close was forced\n"));
+            assertThat(recordingAppender.getMessages(), hasItem("DEBUG - Session shouldCloseSessionOnClientClose closed\n"));
+        }
+
+        // try to reconnect to that session and make sure no state is there
+        final Cluster clusterReconnect = TestClientFactory.open();
+        final Client clientReconnect = clusterReconnect.connect(name.getMethodName());
+
+        // should get an error because "x" is not defined as this is a new session
+        try {
+            clientReconnect.submit("y=100").all().join();
+            clientReconnect.submit("x").all().join();
+            fail("Should not have been successful as 'x' was only defined in the old session");
+        } catch(Exception ex) {
+            final Throwable root = ExceptionUtils.getRootCause(ex);
+            assertThat(root.getMessage(), startsWith("No such property"));
+        }
+
+        // the commit from client1 should not have gone through so there should be no data present.
+        assertEquals(0, clientReconnect.submit("graph.traversal().V().count()").all().join().get(0).getInt());
+
+        // must turn on maintainStateAfterException for unified channelizer
+        if (!isUsingUnifiedChannelizer()) {
+            assertEquals(100, clientReconnect.submit("y").all().join().get(0).getInt());
+        }
+
+        clusterReconnect.close();
+
+        if (isUsingUnifiedChannelizer()) {
+            assertEquals(0, ((UnifiedChannelizer) server.getChannelizer()).getUnifiedHandler().getActiveSessionCount());
+        }
+    }
+
+    @Test
+    public void shouldCloseSessionOnClientCloseWithStateMaintainedBetweenExceptions() throws Exception {
+        assumeNeo4jIsPresent();
+        assumeThat("Must use UnifiedChannelizer", isUsingUnifiedChannelizer(), is(true));
+
+        final Cluster cluster1 = TestClientFactory.open();
+        final Client client1 = cluster1.connect(name.getMethodName());
+        client1.submit("x = 1").all().join();
+        client1.submit("graph.addVertex()").all().join();
+        client1.close();
+        cluster1.close();
+
+        assertThat(((UnifiedChannelizer) server.getChannelizer()).getUnifiedHandler().isActiveSession(name.getMethodName()), is(false));
+
+        // try to reconnect to that session and make sure no state is there
+        final Cluster clusterReconnect = TestClientFactory.open();
+
+        // this configures the client to behave like OpProcessor for UnifiedChannelizer
+        final Client.SessionSettings settings = Client.SessionSettings.build().
+                sessionId(name.getMethodName()).maintainStateAfterException(true).create();
+        final Client clientReconnect = clusterReconnect.connect(Client.Settings.build().useSession(settings).create());
+
+        // should get an error because "x" is not defined as this is a new session
+        try {
+            clientReconnect.submit("y=100").all().join();
+            clientReconnect.submit("x").all().join();
+            fail("Should not have been successful as 'x' was only defined in the old session");
+        } catch(Exception ex) {
+            final Throwable root = ExceptionUtils.getRootCause(ex);
+            assertThat(root.getMessage(), startsWith("No such property"));
+        }
+
+        // the commit from client1 should not have gone through so there should be no data present.
+        assertEquals(0, clientReconnect.submit("graph.traversal().V().count()").all().join().get(0).getInt());
+
+        // since maintainStateAfterException is enabled the UnifiedChannelizer works like OpProcessor
+        assertEquals(100, clientReconnect.submit("y").all().join().get(0).getInt());
+
+        clusterReconnect.close();
+
+        assertEquals(0, ((UnifiedChannelizer) server.getChannelizer()).getUnifiedHandler().getActiveSessionCount());
+    }
+
+    @Test
+    public void shouldUseGlobalFunctionCache() throws Exception {
+        final Cluster cluster = TestClientFactory.open();
+        final Client session = cluster.connect(name.getMethodName());
+        final Client client = cluster.connect();
+
+        assertEquals(3, session.submit("def sumItUp(x,y){x+y};sumItUp(1,2)").all().get().get(0).getInt());
+        assertEquals(3, session.submit("sumItUp(1,2)").all().get().get(0).getInt());
+
+        try {
+            client.submit("sumItUp(1,2)").all().get().get(0).getInt();
+            fail("Global functions should not be cached so the call to sumItUp() should fail");
+        } catch (Exception ex) {
+            final Throwable root = ExceptionUtils.getRootCause(ex);
+            assertThat(root.getMessage(), startsWith("No signature of method"));
         } finally {
             cluster.close();
         }
@@ -150,14 +371,14 @@
         final Client client = cluster.connect(name.getMethodName());
 
         try {
-            assertEquals(3, client.submit("def addItUp(x,y){x+y};addItUp(1,2)").all().get().get(0).getInt());
+            assertEquals(3, client.submit("def sumItUp(x,y){x+y};sumItUp(1,2)").all().get().get(0).getInt());
         } catch (Exception ex) {
             cluster.close();
             throw ex;
         }
 
         try {
-            client.submit("addItUp(1,2)").all().get().get(0).getInt();
+            client.submit("sumItUp(1,2)").all().get().get(0).getInt();
             fail("Global functions should not be cached so the call to addItUp() should fail");
         } catch (Exception ex) {
             final Throwable root = ExceptionUtils.getRootCause(ex);
@@ -168,85 +389,24 @@
     }
 
     @Test
-    public void shouldBlockAdditionalRequestsDuringClose() throws Exception {
-        assumeNeo4jIsPresent();
-
-        // this is sorta cobbled together a bit given limits/rules about how you can use Cluster/Client instances.
-        // basically, we need one to submit the long run job and one to do the close operation that will cancel the
-        // long run job. it is probably possible to do this with some low-level message manipulation but that's
-        // probably not necessary
-        //
-        // this test wont work so well once we remove the sending of the session close message from the driver which
-        // got deprecated at 3.3.11 and lock a session to the connection that created it. in that case, two Client
-        // instances won't be able to connect to the same session which is what is happening below. not sure what
-        // form this test should take then especially since transactions will force close when the channel closes.
-        // perhaps it should just be removed.
+    public void shouldNotAllowMoreThanOneClientPerSession() throws Exception {
         final Cluster cluster1 = TestClientFactory.open();
         final Client client1 = cluster1.connect(name.getMethodName());
-        client1.submit("graph.addVertex()").all().join();
-        final Cluster cluster2 = TestClientFactory.open();
-        final Client client2 = cluster2.connect(name.getMethodName());
-        client2.submit("1+1").all().join();
-
-        final ResultSet rs = client1.submit("Thread.sleep(3000);1+1");
-
-        // close while the previous request is still executing
-        client2.close();
-
-        assertEquals(2, rs.all().join().get(0).getInt());
-
-        client1.close();
-
-        cluster1.close();
-        cluster2.close();
-
-        // triggered an error during close and since we didn't force close, the attempt to close the transaction
-        // is made
-        assertThat(recordingAppender.getMessages(), hasItem("INFO - Rolling back open transactions on graph before killing session: " + name.getMethodName() + "\n"));
-
-    }
-
-    @Test
-    public void shouldBlockAdditionalRequestsDuringForceClose() throws Exception {
-        assumeNeo4jIsPresent();
-
-        // this is sorta cobbled together a bit given limits/rules about how you can use Cluster/Client instances.
-        // basically, we need one to submit the long run job and one to do the close operation that will cancel the
-        // long run job. it is probably possible to do this with some low-level message manipulation but that's
-        // probably not necessary
-        //
-        // this test wont work so well once we remove the sending of the session close message from the driver which
-        // got deprecated at 3.3.11 and lock a session to the connection that created it. in that case, two Client
-        // instances won't be able to connect to the same session which is what is happening below. not sure what
-        // form this test should take then especially since transactions will force close when the channel closes.
-        // perhaps it should just be removed.
-        final Cluster cluster1 = TestClientFactory.open();
-        final Client client1 = cluster1.connect(name.getMethodName());
-        client1.submit("graph.addVertex()").all().join();
+        client1.submit("1+1").all().join();
         final Cluster cluster2 = TestClientFactory.open();
         final Client.SessionSettings sessionSettings = Client.SessionSettings.build()
                 .sessionId(name.getMethodName())
                 .forceClosed(true).create();
         final Client client2 = cluster2.connect(Client.Settings.build().useSession(sessionSettings).create());
-        client2.submit("1+1").all().join();
-
-        final ResultSet rs = client1.submit("Thread.sleep(10000);1+1");
-
-        client2.close();
-
-        // because the close was forced, the message should appear immediately
-        assertThat(recordingAppender.getMessages(), hasItem("INFO - Skipped attempt to close open graph transactions on " + name.getMethodName() + " - close was forced\n"));
 
         try {
-            rs.all().join();
-            fail("The close of the session on client2 should have interrupted the script sent on client1");
+            client2.submit("2+2").all().join();
+            fail("Can't have more than one client connecting to the same session");
         } catch (Exception ex) {
             final Throwable root = ExceptionUtils.getRootCause(ex);
-            assertThat(root.getMessage(), startsWith("Evaluation exceeded the configured 'evaluationTimeout' threshold of 30000 ms or evaluation was otherwise cancelled directly for request"));
+            assertEquals("Session shouldNotAllowMoreThanOneClientPerSession is not bound to the connecting client", root.getMessage());
         }
 
-        client1.close();
-
         cluster1.close();
         cluster2.close();
     }
@@ -263,15 +423,16 @@
             fail("Should have tossed the manually generated exception");
         } catch (Exception ex) {
             final Throwable root = ExceptionUtils.getRootCause(ex);
-            ex.printStackTrace();
             assertEquals("no worky", root.getMessage());
 
-            // just force a commit here of "something" in case there is something lingering
+            // just force a commit here of "something" to ensure the rollback of the previous request
             client.submit("graph.addVertex(); graph.tx().commit()").all().get();
         }
 
         // the transaction is managed so a rollback should have executed
         assertEquals(1, client.submit("g.V().count()").all().get().get(0).getInt());
+
+        cluster.close();
     }
 
     @Test
@@ -304,44 +465,66 @@
             cluster.close();
         }
 
-        assertEquals(1, recordingAppender.getMessages().stream()
-                .filter(msg -> msg.equals("INFO - Session shouldCloseSessionOnceOnRequest closed\n")).count());
+        if (isUsingUnifiedChannelizer()) {
+            assertThat(((UnifiedChannelizer) server.getChannelizer()).getUnifiedHandler().isActiveSession(name.getMethodName()), is(false));
+        } else {
+            assertEquals(1, recordingAppender.getMessages().stream()
+                    .filter(msg -> msg.equals("DEBUG - Session shouldCloseSessionOnceOnRequest closed\n")).count());
+        }
     }
 
     @Test
     public void shouldHaveTheSessionTimeout() throws Exception {
         final Cluster cluster = TestClientFactory.open();
-        final Client client = cluster.connect(name.getMethodName());
+        final Client.SessionSettings settings = Client.SessionSettings.build().
+                sessionId(name.getMethodName()).maintainStateAfterException(true).create();
+        final Client session = cluster.connect(Client.Settings.build().useSession(settings).create());
 
-        final ResultSet results1 = client.submit("x = [1,2,3,4,5,6,7,8,9]");
+        final ResultSet results1 = session.submit("x = [1,2,3,4,5,6,7,8,9]");
         final AtomicInteger counter = new AtomicInteger(0);
         results1.stream().map(i -> i.get(Integer.class) * 2).forEach(i -> assertEquals(counter.incrementAndGet() * 2, Integer.parseInt(i.toString())));
 
-        final ResultSet results2 = client.submit("x[0]+1");
+        final ResultSet results2 = session.submit("x[0]+1");
         assertEquals(2, results2.all().get().get(0).getInt());
 
-        // session times out in 3 seconds
-        Thread.sleep(3500);
+        // session times out in 3 seconds but slow environments like travis might not be so exacting in the
+        // shutdown process so be patient
+        if (isUsingUnifiedChannelizer()) {
+            boolean sessionAlive = true;
+            for (int ix = 1; ix < 11; ix++) {
+                sessionAlive = ((UnifiedChannelizer) server.getChannelizer()).getUnifiedHandler().isActiveSession(name.getMethodName());
+                if (!sessionAlive) break;
+                Thread.sleep(ix * 500);
+            }
+
+            assertThat(sessionAlive, is(false));
+        } else {
+            Thread.sleep(5000);
+        }
 
         try {
             // the original session should be dead so this call will open a new session with the same name but fail
-            // because the state is now gone - x is an invalid property
-            client.submit("x[1]+2").all().get();
+            // because the state is now gone - x is an invalid property.
+            session.submit("x[1]+2").all().get();
             fail("Session should be dead");
         } catch (Exception ex) {
             final Throwable cause = ExceptionUtils.getCause(ex);
             assertThat(cause, instanceOf(ResponseException.class));
-            assertEquals(ResponseStatusCode.SERVER_ERROR_SCRIPT_EVALUATION, ((ResponseException) cause).getResponseStatusCode());
+            assertEquals(ResponseStatusCode.SERVER_ERROR_EVALUATION, ((ResponseException) cause).getResponseStatusCode());
 
             // validate that we can still send messages to the server
-            assertEquals(2, client.submit("1+1").all().join().get(0).getInt());
+            assertEquals(2, session.submit("1+1").all().join().get(0).getInt());
         } finally {
             cluster.close();
         }
 
-        // there will be one for the timeout and a second for closing the cluster
-        assertEquals(2, recordingAppender.getMessages().stream()
-                .filter(msg -> msg.equals("INFO - Session shouldHaveTheSessionTimeout closed\n")).count());
+        if (isUsingUnifiedChannelizer()) {
+            assertThat(((UnifiedChannelizer) server.getChannelizer()).getUnifiedHandler().isActiveSession(name.getMethodName()), is(false));
+        } else {
+            // there will be one for the timeout and a second for closing the cluster
+            assertEquals(2, recordingAppender.getMessages().stream()
+                    .filter(msg -> msg.equals("DEBUG - Session shouldHaveTheSessionTimeout closed\n")).count());
+        }
     }
 
     @Test
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSslIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSslIntegrateTest.java
index 8e1e8fb..d8f4bbe 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSslIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSslIntegrateTest.java
@@ -40,10 +40,6 @@
 import static org.junit.Assert.fail;
 
 public class GremlinServerSslIntegrateTest extends AbstractGremlinServerIntegrationTest {
-    private static final String PEM_SERVER_KEY = "src/test/resources/server.key.pk8";
-    private static final String PEM_SERVER_CRT = "src/test/resources/server.crt";
-    private static final String PEM_CLIENT_KEY = "src/test/resources/client.key.pk8";
-    private static final String PEM_CLIENT_CRT = "src/test/resources/client.crt";
 
     /**
      * Configure specific Gremlin Server settings for specific tests.
@@ -65,28 +61,6 @@
                 settings.ssl.enabled = true;
                 settings.ssl.overrideSslContext(createServerSslContext());
                 break;
-            case "shouldEnableSslAndClientCertificateAuthWithLegacyPem":
-            case "shouldEnableSslAndClientCertificateAuthAndFailWithoutCertWithLegacyPem":
-                settings.ssl = new Settings.SslSettings();
-                settings.ssl.enabled = true;
-                settings.ssl.needClientAuth = ClientAuth.REQUIRE;
-                settings.ssl.keyCertChainFile = PEM_SERVER_CRT;
-                settings.ssl.keyFile = PEM_SERVER_KEY;
-                settings.ssl.keyPassword = KEY_PASS;
-                // Trust the client
-                settings.ssl.trustCertChainFile = PEM_CLIENT_CRT;
-                break;
-            // Trust the client
-            case "shouldEnableSslAndClientCertificateAuthAndFailWithoutTrustedClientCertWithLegacyPem":
-                settings.ssl = new Settings.SslSettings();
-                settings.ssl.enabled = true;
-                settings.ssl.needClientAuth = ClientAuth.REQUIRE;
-                settings.ssl.keyCertChainFile = PEM_SERVER_CRT;
-                settings.ssl.keyFile = PEM_SERVER_KEY;
-                settings.ssl.keyPassword = KEY_PASS;
-                // Trust ONLY the server cert
-                settings.ssl.trustCertChainFile = PEM_SERVER_CRT;
-                break;
             case "shouldEnableSslAndClientCertificateAuthWithPkcs12":
                 settings.ssl = new Settings.SslSettings();
                 settings.ssl.enabled = true;
@@ -211,54 +185,6 @@
     }
 
     @Test
-    public void shouldEnableSslAndClientCertificateAuthWithLegacyPem() {
-        final Cluster cluster = TestClientFactory.build().enableSsl(true)
-                .keyCertChainFile(PEM_CLIENT_CRT).keyFile(PEM_CLIENT_KEY)
-                .keyPassword(KEY_PASS).trustCertificateChainFile(PEM_SERVER_CRT).create();
-        final Client client = cluster.connect();
-
-        try {
-            assertEquals("test", client.submit("'test'").one().getString());
-        } finally {
-            cluster.close();
-        }
-    }
-
-    @Test
-    public void shouldEnableSslAndClientCertificateAuthAndFailWithoutCertWithLegacyPem() {
-        final Cluster cluster = TestClientFactory.build().enableSsl(true).keyStore(JKS_SERVER_KEY).keyStorePassword(KEY_PASS).sslSkipCertValidation(true).create();
-        final Client client = cluster.connect();
-
-        try {
-            client.submit("'test'").one();
-            fail("Should throw exception because ssl client auth is enabled on the server but client does not have a cert");
-        } catch(Exception x) {
-            final Throwable root = ExceptionUtils.getRootCause(x);
-            assertThat(root, instanceOf(NoHostAvailableException.class));
-        } finally {
-            cluster.close();
-        }
-    }
-
-    @Test
-    public void shouldEnableSslAndClientCertificateAuthAndFailWithoutTrustedClientCertWithLegacyPem() {
-        final Cluster cluster = TestClientFactory.build().enableSsl(true)
-                .keyCertChainFile(PEM_CLIENT_CRT).keyFile(PEM_CLIENT_KEY)
-                .keyPassword(KEY_PASS).trustCertificateChainFile(PEM_SERVER_CRT).create();
-        final Client client = cluster.connect();
-
-        try {
-            client.submit("'test'").one();
-            fail("Should throw exception because ssl client auth is enabled on the server but does not trust client's cert");
-        } catch(Exception x) {
-            final Throwable root = ExceptionUtils.getRootCause(x);
-            assertThat(root, instanceOf(NoHostAvailableException.class));
-        } finally {
-            cluster.close();
-        }
-    }
-
-    @Test
     public void shouldEnableSslAndClientCertificateAuthWithPkcs12() {
         final Cluster cluster = TestClientFactory.build().enableSsl(true).keyStore(P12_CLIENT_KEY).keyStorePassword(KEY_PASS)
                 .keyStoreType(KEYSTORE_TYPE_PKCS12).trustStore(P12_CLIENT_TRUST).trustStorePassword(KEY_PASS).create();
@@ -378,42 +304,4 @@
             cluster2.close();
         }
     }
-
-    @Test
-    public void shouldEnableSslAndClientCertificateAuthAndFailWithIncorrectKeyStoreType() {
-        final Cluster cluster = TestClientFactory.build().enableSsl(true)
-                .keyStore(JKS_CLIENT_KEY).keyStorePassword(KEY_PASS).keyStoreType(KEYSTORE_TYPE_PKCS12)
-                .trustStore(P12_CLIENT_TRUST).trustStorePassword(KEY_PASS).trustStoreType(TRUSTSTORE_TYPE_PKCS12)
-                .create();
-        final Client client = cluster.connect();
-
-        try {
-            String res = client.submit("'test'").one().getString();
-            fail("Should throw exception because incorrect keyStoreType is specified");
-        } catch (Exception x) {
-            final Throwable root = ExceptionUtils.getRootCause(x);
-            assertThat(root, instanceOf(NoHostAvailableException.class));
-        } finally {
-            cluster.close();
-        }
-    }
-
-    @Test
-    public void shouldEnableSslAndClientCertificateAuthAndFailWithIncorrectTrustStoreType() {
-        final Cluster cluster = TestClientFactory.build().enableSsl(true)
-                .keyStore(P12_CLIENT_KEY).keyStorePassword(KEY_PASS).keyStoreType(KEYSTORE_TYPE_PKCS12)
-                .trustStore(JKS_CLIENT_TRUST).trustStorePassword(KEY_PASS).trustStoreType(TRUSTSTORE_TYPE_PKCS12)
-                .create();
-        final Client client = cluster.connect();
-
-        try {
-            client.submit("'test'").one();
-            fail("Should throw exception because incorrect trustStoreType is specified");
-        } catch (Exception x) {
-            final Throwable root = ExceptionUtils.getRootCause(x);
-            assertThat(root, instanceOf(NoHostAvailableException.class));
-        } finally {
-            cluster.close();
-        }
-    }
 }
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinSessionTxIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinSessionTxIntegrateTest.java
new file mode 100644
index 0000000..89784f9
--- /dev/null
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinSessionTxIntegrateTest.java
@@ -0,0 +1,324 @@
+/*
+ * 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.server;
+
+import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.apache.tinkerpop.gremlin.driver.Cluster;
+import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.structure.Transaction;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.junit.Test;
+
+import java.io.File;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+/**
+ * Integration tests for gremlin-driver and bytecode sessions.
+ *
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class GremlinSessionTxIntegrateTest extends AbstractGremlinServerIntegrationTest {
+
+    /**
+     * Configure specific Gremlin Server settings for specific tests.
+     */
+    @Override
+    public Settings overrideSettings(final Settings settings) {
+        final String nameOfTest = name.getMethodName();
+
+        deleteDirectory(new File("/tmp/neo4j"));
+        settings.graphs.put("graph", "conf/neo4j-empty.properties");
+
+        switch (nameOfTest) {
+            case "shouldExecuteBytecodeInSession":
+                break;
+        }
+
+        return settings;
+    }
+
+    @Test
+    public void shouldCommitTxBytecodeInSession() throws Exception {
+        assumeNeo4jIsPresent();
+
+        final Cluster cluster = TestClientFactory.build().create();
+        final GraphTraversalSource g = traversal().withRemote(DriverRemoteConnection.using(cluster));
+
+        final GraphTraversalSource gtx = g.tx().begin();
+        assertThat(gtx.tx().isOpen(), is(true));
+
+        gtx.addV("person").iterate();
+        assertEquals(1, (long) gtx.V().count().next());
+
+        // outside the session we should be at zero
+        assertEquals(0, (long) g.V().count().next());
+
+        gtx.tx().commit();
+        assertThat(gtx.tx().isOpen(), is(false));
+
+        // sessionless connections should still be good - close() should not affect that
+        assertEquals(1, (long) g.V().count().next());
+
+        // but the spawned gtx should be dead
+        try {
+            gtx.addV("software").iterate();
+            fail("Should have failed since we committed the transaction");
+        } catch (Exception ex) {
+            final Throwable root = ExceptionUtils.getRootCause(ex);
+            assertEquals("Client is closed", root.getMessage());
+        }
+
+        cluster.close();
+    }
+
+    @Test
+    public void shouldCommitTxBytecodeInSessionWithExplicitTransactionObject() throws Exception {
+        assumeNeo4jIsPresent();
+
+        final Cluster cluster = TestClientFactory.build().create();
+        final GraphTraversalSource g = traversal().withRemote(DriverRemoteConnection.using(cluster));
+        final Transaction tx = g.tx();
+        assertThat(tx.isOpen(), is(true));
+
+        final GraphTraversalSource gtx = tx.begin();
+        gtx.addV("person").iterate();
+        assertEquals(1, (long) gtx.V().count().next());
+        tx.commit();
+        assertThat(tx.isOpen(), is(false));
+
+        // sessionless connections should still be good - close() should not affect that
+        assertEquals(1, (long) g.V().count().next());
+
+        cluster.close();
+    }
+
+    @Test
+    public void shouldRollbackTxBytecodeInSession() throws Exception {
+        assumeNeo4jIsPresent();
+
+        final Cluster cluster = TestClientFactory.build().create();
+        final GraphTraversalSource g = traversal().withRemote(DriverRemoteConnection.using(cluster));
+
+        final GraphTraversalSource gtx = g.tx().begin();
+        assertThat(gtx.tx().isOpen(), is(true));
+
+        gtx.addV("person").iterate();
+        assertEquals(1, (long) gtx.V().count().next());
+        gtx.tx().rollback();
+        assertThat(gtx.tx().isOpen(), is(false));
+
+        // sessionless connections should still be good - close() should not affect that
+        assertEquals(0, (long) g.V().count().next());
+
+        // but the spawned gtx should be dead
+        try {
+            gtx.addV("software").iterate();
+            fail("Should have failed since we committed the transaction");
+        } catch (Exception ex) {
+            final Throwable root = ExceptionUtils.getRootCause(ex);
+            assertEquals("Client is closed", root.getMessage());
+        }
+
+        cluster.close();
+    }
+
+    @Test
+    public void shouldCommitTxBytecodeInSessionOnCloseOfGtx() throws Exception {
+        assumeNeo4jIsPresent();
+
+        final Cluster cluster = TestClientFactory.build().create();
+        final GraphTraversalSource g = traversal().withRemote(DriverRemoteConnection.using(cluster));
+
+        final GraphTraversalSource gtx = g.tx().begin();
+        assertThat(gtx.tx().isOpen(), is(true));
+
+        gtx.addV("person").iterate();
+        assertEquals(1, (long) gtx.V().count().next());
+        gtx.close();
+        assertThat(gtx.tx().isOpen(), is(false));
+
+        // sessionless connections should still be good - close() should not affect that
+        assertEquals(1, (long) g.V().count().next());
+
+        // but the spawned gtx should be dead
+        try {
+            gtx.addV("software").iterate();
+            fail("Should have failed since we committed the transaction");
+        } catch (Exception ex) {
+            final Throwable root = ExceptionUtils.getRootCause(ex);
+            assertEquals("Client is closed", root.getMessage());
+        }
+
+        cluster.close();
+    }
+
+    @Test
+    public void shouldCommitTxBytecodeInSessionOnCloseTx() throws Exception {
+        assumeNeo4jIsPresent();
+
+        final Cluster cluster = TestClientFactory.build().create();
+        final GraphTraversalSource g = traversal().withRemote(DriverRemoteConnection.using(cluster));
+
+        final GraphTraversalSource gtx = g.tx().begin();
+        assertThat(gtx.tx().isOpen(), is(true));
+
+        gtx.addV("person").iterate();
+        assertEquals(1, (long) gtx.V().count().next());
+        gtx.close();
+        assertThat(gtx.tx().isOpen(), is(false));
+
+        // sessionless connections should still be good - close() should not affect that
+        assertEquals(1, (long) g.V().count().next());
+
+        // but the spawned gtx should be dead
+        try {
+            gtx.addV("software").iterate();
+            fail("Should have failed since we committed the transaction");
+        } catch (Exception ex) {
+            final Throwable root = ExceptionUtils.getRootCause(ex);
+            assertEquals("Client is closed", root.getMessage());
+        }
+
+        cluster.close();
+    }
+
+    @Test
+    public void shouldOpenAndCloseObsceneAmountOfSessions() throws Exception {
+        assumeNeo4jIsPresent();
+
+        final Cluster cluster = TestClientFactory.build().create();
+        final GraphTraversalSource g = traversal().withRemote(DriverRemoteConnection.using(cluster));
+
+        // need to open significantly more sessions that we have threads in gremlinPool. if we go too obscene on
+        // OpProcessor this test will take too long
+        final int numberOfSessions = isUsingUnifiedChannelizer() ? 1000 : 100;
+        for (int ix = 0; ix < numberOfSessions; ix ++) {
+            final Transaction tx = g.tx();
+            final GraphTraversalSource gtx = tx.begin();
+            try {
+                final Vertex v1 = gtx.addV("person").property("pid", ix + "a").next();
+                final Vertex v2 = gtx.addV("person").property("pid", ix + "b").next();
+                gtx.addE("knows").from(v1).to(v2).iterate();
+                tx.commit();
+            } catch (Exception ex) {
+                tx.rollback();
+                fail("Should not expect any failures");
+            } finally {
+                assertThat(tx.isOpen(), is(false));
+            }
+        }
+
+        // sessionless connections should still be good - close() should not affect that
+        assertEquals(numberOfSessions * 2, (long) g.V().count().next());
+        assertEquals(numberOfSessions, (long) g.E().count().next());
+
+        cluster.close();
+    }
+
+    @Test
+    public void shouldCommitTxBytecodeInSessionReusingGtxAcrossThreads() throws Exception {
+        assumeNeo4jIsPresent();
+
+        final ExecutorService service = Executors.newFixedThreadPool(2);
+
+        final Cluster cluster = TestClientFactory.build().create();
+        final GraphTraversalSource g = traversal().withRemote(DriverRemoteConnection.using(cluster));
+
+        final GraphTraversalSource gtx = g.tx().begin();
+        assertThat(gtx.tx().isOpen(), is(true));
+
+        final int verticesToAdd = 64;
+        for (int ix = 0; ix < verticesToAdd; ix++) {
+            service.submit(() -> gtx.addV("person").iterate());
+        }
+
+        service.shutdown();
+        service.awaitTermination(90000, TimeUnit.MILLISECONDS);
+
+        // outside the session we should be at zero
+        assertEquals(0, (long) g.V().count().next());
+
+        assertEquals(verticesToAdd, (long) gtx.V().count().next());
+        gtx.tx().commit();
+        assertThat(gtx.tx().isOpen(), is(false));
+
+        // sessionless connections should still be good - close() should not affect that
+        assertEquals(verticesToAdd, (long) g.V().count().next());
+
+        cluster.close();
+    }
+
+    @Test
+    public void shouldSpawnMultipleTraversalSourceInSameTransaction() throws Exception {
+        assumeNeo4jIsPresent();
+
+        final Cluster cluster = TestClientFactory.build().create();
+        final GraphTraversalSource g = traversal().withRemote(DriverRemoteConnection.using(cluster));
+
+        final Transaction tx1 = g.tx();
+        final GraphTraversalSource gtx1a = tx1.begin();
+        final GraphTraversalSource gtx1b = tx1.begin();
+        final Transaction tx2 = g.tx();
+        final GraphTraversalSource gtx2 = tx2.begin();
+
+        gtx1a.addV("person").iterate();
+        assertEquals(1, (long) gtx1a.V().count().next());
+        assertEquals(1, (long) gtx1b.V().count().next());
+
+        // outside the session we should be at zero
+        assertEquals(0, (long) g.V().count().next());
+        assertEquals(0, (long) gtx2.V().count().next());
+
+        // either can commit to end the transaction
+        gtx1b.tx().commit();
+        assertThat(gtx1a.tx().isOpen(), is(false));
+        assertThat(gtx1b.tx().isOpen(), is(false));
+
+        // sessionless connections should still be good - close() should not affect that
+        assertEquals(1, (long) g.V().count().next());
+
+        // but the spawned gtx should be dead
+        try {
+            gtx1a.addV("software").iterate();
+            fail("Should have failed since we committed the transaction");
+        } catch (Exception ex) {
+            final Throwable root = ExceptionUtils.getRootCause(ex);
+            assertEquals("Client is closed", root.getMessage());
+        }
+
+        try {
+            gtx1b.addV("software").iterate();
+            fail("Should have failed since we committed the transaction");
+        } catch (Exception ex) {
+            final Throwable root = ExceptionUtils.getRootCause(ex);
+            assertEquals("Client is closed", root.getMessage());
+        }
+
+        cluster.close();
+    }
+}
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/KdcFixture.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/KdcFixture.java
deleted file mode 100644
index c4bcaed..0000000
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/KdcFixture.java
+++ /dev/null
@@ -1,185 +0,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.
- */
-package org.apache.tinkerpop.gremlin.server;
-
-import org.apache.kerby.kerberos.kerb.KrbException;
-import org.apache.kerby.kerberos.kerb.client.KrbClient;
-import org.apache.kerby.kerberos.kerb.client.KrbConfig;
-import org.apache.kerby.kerberos.kerb.client.KrbConfigKey;
-import org.apache.kerby.kerberos.kerb.server.SimpleKdcServer;
-import org.apache.kerby.kerberos.kerb.type.ticket.TgtTicket;
-import org.apache.kerby.util.NetworkUtil;
-import org.slf4j.LoggerFactory;
-
-import java.io.File;
-import java.net.Inet4Address;
-
-
-/**
- * This class is derived from the following classes from https://github.com/apache/directory-kerby/blob/kerby-all-1.0.0-RC2:
- *  - org.apache.kerby.kerberos.kerb.server.TestKdcServer
- *  - org.apache.kerby.kerberos.kerb.server.KdcTestBase
- *  - org.apache.kerby.kerberos.kerb.server.LoginTestBase
- *
- * See also: gremlin-server/src/main/static/NOTICE
- *
- * @author Marc de Lignie
- */
-public class KdcFixture {
-
-    private static final org.slf4j.Logger logger = LoggerFactory.getLogger(KdcFixture.class);
-
-    final String clientPassword = "123456";
-    final String clientPassword2 = "1234562";
-    final String clientPrincipalName = "drankye";
-    final String clientPrincipalName2 = "drankye2";
-    final String serverPrincipalName = "test-service";
-    final String ticketCacheFileName = "test-tkt.cc";
-    final String ticketCacheFileName2 = "test-tkt2.cc";
-    final String serviceKeytabFileName = "test-service.keytab";
-
-    final String clientPrincipal;
-    final String clientPrincipal2;
-    final String serverPrincipal;
-    final File testDir;
-    final File ticketCacheFile;
-    final File ticketCacheFile2;
-    final File serviceKeytabFile;
-
-    final String hostname;
-    private SimpleKdcServer kdcServer;
-
-    public KdcFixture(final String authConfigName) {
-        System.setProperty("java.security.auth.login.config", authConfigName);
-        hostname = findHostname();
-        serverPrincipal = serverPrincipalName + "/" + hostname + "@" + KdcFixture.TestKdcServer.KDC_REALM;
-        clientPrincipal = clientPrincipalName + "@" + KdcFixture.TestKdcServer.KDC_REALM;
-        clientPrincipal2 = clientPrincipalName2 + "@" + KdcFixture.TestKdcServer.KDC_REALM;
-        testDir = createTestDir();
-        ticketCacheFile = new File(testDir, ticketCacheFileName);
-        ticketCacheFile2 = new File(testDir, ticketCacheFileName2);
-        serviceKeytabFile = new File(testDir, serviceKeytabFileName);
-    }
-
-    private String findHostname() {
-        // Hostname setting must be consistent with the way gremlin-console sets gremlin-server's hostname
-        // and derives gremlin-server's principal name. Also, the hostname needs to be lowercase for use
-        // in principal names.
-        String hostname = "";
-        try {
-            hostname = Inet4Address.getLocalHost().getCanonicalHostName().toLowerCase();
-        } catch (Exception e) {
-            logger.error("Hostname not found: " + e.getMessage());
-        }
-        return hostname;
-    }
-
-    private File createTestDir() {
-        final String basedir = System.getProperty("basedir");
-        final File targetdir = new File(basedir, "target");
-        final File testDir = new File(targetdir, "kdc");
-        testDir.mkdirs();
-        return testDir;
-    }
-
-    private static class TestKdcServer extends SimpleKdcServer {
-        public static final String KDC_REALM = "TEST.COM";
-        public static final String HOSTNAME = "localhost";
-
-        TestKdcServer() throws KrbException {
-            setKdcRealm(KDC_REALM);
-            setKdcHost(HOSTNAME);
-            setAllowTcp(true);
-            setAllowUdp(false);    // There are still udp issues in Apache Directory-Kerby 1.0.0-RC2
-            setKdcTcpPort(NetworkUtil.getServerPort());
-
-            final KrbClient krbClnt = getKrbClient();
-            final KrbConfig krbConfig = krbClnt.getKrbConfig();
-            krbConfig.setString(KrbConfigKey.PERMITTED_ENCTYPES,
-                    "aes128-cts-hmac-sha1-96 des-cbc-crc des-cbc-md5 des3-cbc-sha1");
-            krbClnt.setTimeout(10 * 1000);
-        }
-    }
-
-    public void setUp() throws Exception {
-        setUpKdcServer();
-        setUpPrincipals();
-    }
-
-    private void setUpKdcServer() throws Exception {
-        kdcServer = new TestKdcServer();
-        kdcServer.setWorkDir(testDir);
-        kdcServer.init();
-        kdcServer.start();
-    }
-
-    private void setUpPrincipals() throws KrbException {
-        kdcServer.createPrincipals(serverPrincipal);
-        kdcServer.exportPrincipal(serverPrincipal, serviceKeytabFile);
-
-        kdcServer.createPrincipal(clientPrincipal, clientPassword);
-        final TgtTicket tgt = kdcServer.getKrbClient().requestTgt(clientPrincipal, clientPassword);
-        kdcServer.getKrbClient().storeTicket(tgt, ticketCacheFile);
-
-        kdcServer.createPrincipal(clientPrincipal2, clientPassword2);
-        final TgtTicket tgt2 = kdcServer.getKrbClient().requestTgt(clientPrincipal2, clientPassword2);
-        kdcServer.getKrbClient().storeTicket(tgt2, ticketCacheFile2);
-    }
-
-    public void close() {
-        deletePrincipals();
-
-        try {
-            kdcServer.stop();
-        } catch (KrbException krbex) {
-            logger.warn("Tried to stop KdcServer but encountered an exception", krbex);
-        }
-
-        ticketCacheFile.delete();
-        ticketCacheFile2.delete();
-        serviceKeytabFile.delete();
-        testDir.delete();
-
-        System.clearProperty("java.security.auth.login.config");
-    }
-
-    void deletePrincipals() {
-        try {
-            kdcServer.getKadmin().deleteBuiltinPrincipals();
-        } catch (KrbException krbex) {
-            logger.warn("Tried to delete builtin Principals on teardown but failed", krbex);
-        }
-
-        deletePrincipal(serverPrincipal);
-        deletePrincipal(clientPrincipal);
-        deletePrincipal(clientPrincipal2);
-    }
-
-    private void deletePrincipal(final String principalToDelete) {
-        try {
-            kdcServer.deletePrincipal(principalToDelete);
-        } catch (KrbException krbex) {
-            logger.warn(String.format("Tried to delete %s Principals on teardown but failed", principalToDelete), krbex);
-        }
-    }
-
-    public void createPrincipal(final String principal) throws KrbException {
-        kdcServer.createPrincipal(principal);
-    }
-}
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/KdcFixtureTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/KdcFixtureTest.java
index bc3c792..ad49698 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/KdcFixtureTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/KdcFixtureTest.java
@@ -28,9 +28,10 @@
     @Test
     public void shouldCloseCleanly() throws Exception {
         final KdcFixture kdc;
-        final String buildDir = System.getProperty("build.dir");
-        kdc = new KdcFixture(buildDir +
-                "/test-classes/org/apache/tinkerpop/gremlin/server/gremlin-console-jaas.conf");
+        final String moduleBaseDir = System.getProperty("basedir");
+        final String authConfigName = moduleBaseDir + "/src/test/resources/org/apache/tinkerpop/gremlin/server/gremlin-console-jaas.conf";
+        System.setProperty("java.security.auth.login.config", authConfigName);
+        kdc = new KdcFixture(moduleBaseDir);
         kdc.setUp();
 
         // deleting the principals will force an exception when they are deleted a second time on close
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/ResponseHandlerContextTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/ResponseHandlerContextTest.java
deleted file mode 100644
index b072c21..0000000
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/ResponseHandlerContextTest.java
+++ /dev/null
@@ -1,161 +0,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.
- */
-package org.apache.tinkerpop.gremlin.server;
-
-import io.netty.channel.ChannelHandlerContext;
-import org.apache.log4j.Level;
-import org.apache.log4j.Logger;
-import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
-import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
-import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
-import org.apache.tinkerpop.gremlin.server.handler.Frame;
-import org.apache.tinkerpop.gremlin.util.Log4jRecordingAppender;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.mockito.Mockito;
-
-import java.util.Arrays;
-import java.util.UUID;
-import java.util.function.BiFunction;
-
-import static org.junit.Assert.assertTrue;
-
-@RunWith(Parameterized.class)
-public class ResponseHandlerContextTest {
-
-    @Parameterized.Parameter(value = 0)
-    public BiFunction<Context, ResponseStatusCode, Void> writeInvoker;
-
-    private final ChannelHandlerContext ctx = Mockito.mock(ChannelHandlerContext.class);
-    private final RequestMessage request = RequestMessage.build("test").create();
-    private final Context context = new Context(request, ctx, null, null, null, null);
-    private final Log4jRecordingAppender recordingAppender = new Log4jRecordingAppender();
-
-    private Level originalLogLevel;
-
-    @Parameterized.Parameters(name = "{0}")
-    public static Iterable<Object[]> data() {
-        return Arrays.asList(new Object[][] {
-            {
-                new BiFunction<Context, ResponseStatusCode, Void>() {
-                    @Override
-                    public Void apply(final Context context, final ResponseStatusCode code) {
-                        context.writeAndFlush(code, "testMessage");
-                        return null;
-                    }
-
-                    @Override
-                    public String toString() {
-                        return "writeAndFlush(ResponseStatusCode, Object)";
-                    }
-                }
-            }, {
-                new BiFunction<Context, ResponseStatusCode, Void>() {
-                    @Override
-                    public Void apply(final Context context, final ResponseStatusCode code) {
-                        context.writeAndFlush(ResponseMessage.build(UUID.randomUUID()).code(code).create());
-                        return null;
-                    }
-
-                    @Override
-                    public String toString() {
-                        return "writeAndFlush(ResponseMessage)";
-                    }
-                }
-            },
-        });
-    }
-
-    @Before
-    public void addRecordingAppender() {
-        final Logger rootLogger = Logger.getRootLogger();
-        rootLogger.addAppender(recordingAppender);
-        originalLogLevel = rootLogger.getLevel();
-        rootLogger.setLevel(Level.ALL);
-    }
-
-    @After
-    public void removeRecordingAppender() {
-        final Logger rootLogger = Logger.getRootLogger();
-        rootLogger.setLevel(originalLogLevel);
-        rootLogger.removeAppender(recordingAppender);
-    }
-
-    @Test
-    public void shouldAllowMultipleNonFinalResponses() {
-        writeInvoker.apply(context, ResponseStatusCode.AUTHENTICATE);
-        Mockito.verify(ctx, Mockito.times(1)).writeAndFlush(Mockito.any());
-
-        writeInvoker.apply(context, ResponseStatusCode.PARTIAL_CONTENT);
-        Mockito.verify(ctx, Mockito.times(2)).writeAndFlush(Mockito.any());
-
-        writeInvoker.apply(context, ResponseStatusCode.PARTIAL_CONTENT);
-        Mockito.verify(ctx, Mockito.times(3)).writeAndFlush(Mockito.any());
-    }
-
-    @Test
-    public void shouldAllowAtMostOneFinalResponse() {
-        writeInvoker.apply(context, ResponseStatusCode.AUTHENTICATE);
-        Mockito.verify(ctx, Mockito.times(1)).writeAndFlush(Mockito.any());
-
-        writeInvoker.apply(context, ResponseStatusCode.SUCCESS);
-        Mockito.verify(ctx, Mockito.times(2)).writeAndFlush(Mockito.any());
-
-        writeInvoker.apply(context, ResponseStatusCode.SERVER_ERROR_TIMEOUT);
-        assertTrue(recordingAppender.logContainsAny(".*" + request.getRequestId() + ".*"));
-        assertTrue(recordingAppender.logContainsAny(".*" + ResponseStatusCode.SERVER_ERROR_TIMEOUT + ".*"));
-
-        // ensure there were no other writes to the channel
-        Mockito.verify(ctx, Mockito.times(2)).writeAndFlush(Mockito.any());
-    }
-
-    @Test
-    public void shouldNotAllowNonFinalMessagesAfterFinalResponse() {
-        writeInvoker.apply(context, ResponseStatusCode.SERVER_ERROR_TIMEOUT);
-        Mockito.verify(ctx, Mockito.times(1)).writeAndFlush(Mockito.any());
-
-        writeInvoker.apply(context, ResponseStatusCode.PARTIAL_CONTENT);
-        assertTrue(recordingAppender.logContainsAny(".*" + request.getRequestId() + ".*"));
-        assertTrue(recordingAppender.logContainsAny(".*" + ResponseStatusCode.PARTIAL_CONTENT + ".*"));
-
-        // ensure there were no other writes to the channel
-        Mockito.verify(ctx, Mockito.times(1)).writeAndFlush(Mockito.any());
-    }
-
-    @Test
-    public void shouldReleaseIgnoredFrames() {
-        writeInvoker.apply(context, ResponseStatusCode.SERVER_ERROR_TIMEOUT);
-        Mockito.verify(ctx, Mockito.times(1)).writeAndFlush(Mockito.any());
-
-        Frame frame = Mockito.mock(Frame.class);
-        context.writeAndFlush(ResponseStatusCode.SUCCESS, frame);
-
-        assertTrue(recordingAppender.logContainsAny(".*" + request.getRequestId() + ".*"));
-        assertTrue(recordingAppender.logContainsAny(".*" + ResponseStatusCode.SUCCESS + ".*"));
-
-        // ensure there were no other writes to the channel
-        Mockito.verify(ctx, Mockito.times(1)).writeAndFlush(Mockito.any());
-
-        // ensure the frame was released
-        Mockito.verify(frame, Mockito.times(1)).tryRelease();
-    }
-}
\ No newline at end of file
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/TestClientFactory.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/TestClientFactory.java
index 214be01..06ec8c9 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/TestClientFactory.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/TestClientFactory.java
@@ -19,7 +19,6 @@
 package org.apache.tinkerpop.gremlin.server;
 
 import org.apache.tinkerpop.gremlin.driver.Cluster;
-import org.apache.tinkerpop.gremlin.driver.simple.NioClient;
 import org.apache.tinkerpop.gremlin.driver.simple.WebSocketClient;
 
 import java.net.URI;
@@ -31,7 +30,6 @@
 
     public static final int PORT = 45940;
     public static final URI WEBSOCKET_URI = URI.create("ws://localhost:" + PORT + "/gremlin");
-    public static final URI NIO_URI = URI.create("gs://localhost:" + PORT);
     public static final String HTTP = "http://localhost:" + PORT;
     public static final String RESOURCE_PATH = "conf/remote-objects.yaml";
 
@@ -51,10 +49,6 @@
         return new WebSocketClient(WEBSOCKET_URI);
     }
 
-    public static NioClient createNioClient() {
-        return new NioClient(NIO_URI);
-    }
-
     public static String createURLString() {
         return createURLString("");
     }
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/authz/AllowList.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/authz/AllowList.java
new file mode 100644
index 0000000..2d9d509
--- /dev/null
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/authz/AllowList.java
@@ -0,0 +1,70 @@
+/*
+ * 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.server.authz;
+
+import org.yaml.snakeyaml.TypeDescription;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+
+/**
+ * AllowList for the AllowListAuthorizer as configured by a YAML file.
+ *
+ * @author Marc de Lignie
+ */
+public class AllowList {
+
+    /**
+     * Holds lists of groups by grant. A grant is either a TraversalSource name or the "sandbox" value. With the
+     * sandbox grant users can access all TraversalSource instances and execute groovy scripts as string based
+     * requests or as lambda functions, only limited by Gremlin Server's sandbox definition.
+     */
+    public Map<String, List<String>> grants;
+
+    /**
+     * Holds lists of user names by groupname. The "anonymous" user name can be used to denote any user.
+     */
+    public Map<String, List<String>> groups;
+
+    /**
+     * Read a configuration from a YAML file into an {@link AllowList} object.
+     *
+     * @param file the location of a AllowList YAML configuration file
+     * @return An {@link Optional} object wrapping the created {@link AllowList}
+     */
+    public static AllowList read(final String file) throws Exception {
+        final InputStream stream = new FileInputStream(new File(file));
+
+        final Constructor constructor = new Constructor(AllowList.class);
+        final TypeDescription allowListDescription = new TypeDescription(AllowList.class);
+        allowListDescription.putMapPropertyType("grants", String.class, Object.class);
+        allowListDescription.putMapPropertyType("groups", String.class, Object.class);
+        constructor.addTypeDescription(allowListDescription);
+
+        final Yaml yaml = new Yaml(constructor);
+        return yaml.loadAs(stream, AllowList.class);
+    }
+}
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/authz/AllowListAuthorizer.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/authz/AllowListAuthorizer.java
new file mode 100644
index 0000000..7d4c604
--- /dev/null
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/authz/AllowListAuthorizer.java
@@ -0,0 +1,152 @@
+/*
+ * 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.server.authz;
+
+import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
+import org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.verification.VertexProgramRestrictionStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.util.BytecodeHelper;
+import org.apache.tinkerpop.gremlin.server.Settings.AuthorizationSettings;
+import org.apache.tinkerpop.gremlin.server.auth.AuthenticatedUser;
+
+import java.util.*;
+
+
+/**
+ * Authorizes a user per request, based on a list that grants access to {@link TraversalSource} instances for
+ * bytecode requests and to gremlin server's sandbox for string requests and lambdas. The {@link
+ * AuthorizationSettings}.config must have an authorizationAllowList entry that contains the name of a YAML file.
+ * This authorizer is for demonstration purposes only. It does not scale well in the number of users regarding
+ * memory usage and administrative burden.
+ *
+ * @author Marc de Lignie
+ */
+public class AllowListAuthorizer implements Authorizer {
+
+    public static final String SANDBOX = "sandbox";
+    public static final String REJECT_BYTECODE = "User not authorized for bytecode requests on %s";
+    public static final String REJECT_LAMBDA = "lambdas";
+    public static final String REJECT_MUTATE = "the ReadOnlyStrategy";
+    public static final String REJECT_OLAP = "the VertexProgramRestrictionStrategy";
+    public static final String REJECT_SUBGRAPH = "the SubgraphStrategy";
+    public static final String REJECT_STRING = "User not authorized for string-based requests.";
+    public static final String KEY_AUTHORIZATION_ALLOWLIST = "authorizationAllowList";
+
+    // Collections derived from the list with allowed users for fast lookups
+    private final Map<String, List<String>> usernamesByTraversalSource = new HashMap<>();
+    private final Set<String> usernamesSandbox = new HashSet<>();
+
+    /**
+     * This method is called once upon system startup to initialize the {@code AllowListAuthorizer}.
+     */
+    @Override
+    public void setup(final Map<String,Object> config) {
+        AllowList allowList;
+        final String file = (String) config.get(KEY_AUTHORIZATION_ALLOWLIST);
+
+        try {
+            allowList = AllowList.read(file);
+        } catch (Exception e) {
+            throw new IllegalArgumentException(String.format("Failed to read list with allowed users from %s", file));
+        }
+        for (Map.Entry<String, List<String>> entry : allowList.grants.entrySet()) {
+            if (!entry.getKey().equals(SANDBOX)) {
+                usernamesByTraversalSource.put(entry.getKey(), new ArrayList<>());
+            }
+            for (final String group : entry.getValue()) {
+                if (allowList.groups.get(group) == null) {
+                    throw new RuntimeException(String.format("Group '%s' not defined in file with allowed users.", group));
+                }
+                if (entry.getKey().equals(SANDBOX)) {
+                    usernamesSandbox.addAll(allowList.groups.get(group));
+                } else {
+                    usernamesByTraversalSource.get(entry.getKey()).addAll(allowList.groups.get(group));
+                }
+            }
+        }
+    }
+
+    /**
+     * Checks whether a user is authorized to have a gremlin bytecode request from a client answered and raises an
+     * {@link AuthorizationException} if this is not the case. For a request to be authorized, the user must either
+     * have a grant for the requested {@link TraversalSource}, without using lambdas, mutating steps or OLAP, or have a
+     * sandbox grant.
+     *
+     * @param user {@link AuthenticatedUser} that needs authorization.
+     * @param bytecode The gremlin {@link Bytecode} request to authorize the user for.
+     * @param aliases A {@link Map} with a single key/value pair that maps the name of the {@link TraversalSource} in the
+     *                {@link Bytecode} request to name of one configured in Gremlin Server.
+     * @return The original or modified {@link Bytecode} to be used for further processing.
+     */
+    @Override
+    public Bytecode authorize(final AuthenticatedUser user, final Bytecode bytecode, final Map<String, String> aliases) throws AuthorizationException {
+        final Set<String> usernames = new HashSet<>();
+
+        for (final String resource: aliases.values()) {
+            usernames.addAll(usernamesByTraversalSource.get(resource));
+        }
+        final boolean userHasTraversalSourceGrant = usernames.contains(user.getName()) || usernames.contains(AuthenticatedUser.ANONYMOUS_USERNAME);
+        final boolean userHasSandboxGrant = usernamesSandbox.contains(user.getName()) || usernamesSandbox.contains(AuthenticatedUser.ANONYMOUS_USERNAME);
+        final boolean runsLambda = BytecodeHelper.getLambdaLanguage(bytecode).isPresent();
+        final boolean touchesReadOnlyStrategy = bytecode.toString().contains(ReadOnlyStrategy.class.getSimpleName());
+        final boolean touchesOLAPRestriction = bytecode.toString().contains(VertexProgramRestrictionStrategy.class.getSimpleName());
+        // This element becomes obsolete after resolving TINKERPOP-2473 for allowing only a single instance of each traversal strategy.
+        final boolean touchesSubgraphStrategy = bytecode.toString().contains(SubgraphStrategy.class.getSimpleName());
+
+        final List<String> rejections = new ArrayList<>();
+        if (runsLambda) {
+            rejections.add(REJECT_LAMBDA);
+        }
+        if (touchesReadOnlyStrategy) {
+            rejections.add(REJECT_MUTATE);
+        }
+        if (touchesOLAPRestriction) {
+            rejections.add(REJECT_OLAP);
+        }
+        if (touchesSubgraphStrategy) {
+            rejections.add(REJECT_SUBGRAPH);
+        }
+        String rejectMessage = REJECT_BYTECODE;
+        if (rejections.size() > 0) {
+            rejectMessage += " using " + String.join(", ", rejections);
+        }
+        rejectMessage += ".";
+
+        if ( (!userHasTraversalSourceGrant || runsLambda || touchesOLAPRestriction || touchesReadOnlyStrategy || touchesSubgraphStrategy) && !userHasSandboxGrant) {
+            throw new AuthorizationException(String.format(rejectMessage, aliases.values()));
+        }
+        return bytecode;
+    }
+
+    /**
+     * Checks whether a user is authorized to have a script request from a gremlin client answered and raises an
+     * {@link AuthorizationException} if this is not the case.
+     *
+     * @param user {@link AuthenticatedUser} that needs authorization.
+     * @param msg {@link RequestMessage} in which the {@link org.apache.tinkerpop.gremlin.driver.Tokens}.ARGS_GREMLIN argument can contain an arbitrary succession of script statements.
+     */
+    public void authorize(final AuthenticatedUser user, final RequestMessage msg) throws AuthorizationException {
+        if (!usernamesSandbox.contains(user.getName())) {
+            throw new AuthorizationException(REJECT_STRING);
+        }
+    }
+}
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/authz/AuthorizerTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/authz/AuthorizerTest.java
new file mode 100644
index 0000000..1b30c24
--- /dev/null
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/authz/AuthorizerTest.java
@@ -0,0 +1,278 @@
+/*
+ * 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.server.authz;
+
+import org.apache.tinkerpop.gremlin.driver.Tokens;
+import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
+import org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.verification.VertexProgramRestrictionStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy;
+import org.apache.tinkerpop.gremlin.server.auth.AuthenticatedUser;
+import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
+import org.apache.tinkerpop.gremlin.util.function.Lambda;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.Supplier;
+
+import static org.apache.tinkerpop.gremlin.server.authz.AllowListAuthorizer.REJECT_BYTECODE;
+import static org.apache.tinkerpop.gremlin.server.authz.AllowListAuthorizer.REJECT_LAMBDA;
+import static org.apache.tinkerpop.gremlin.server.authz.AllowListAuthorizer.REJECT_MUTATE;
+import static org.apache.tinkerpop.gremlin.server.authz.AllowListAuthorizer.REJECT_OLAP;
+import static org.apache.tinkerpop.gremlin.server.authz.AllowListAuthorizer.REJECT_SUBGRAPH;
+import static org.apache.tinkerpop.gremlin.server.authz.AllowListAuthorizer.REJECT_STRING;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+
+/**
+ * @author Marc de Lignie
+ *
+ * Run with:
+ * mvn test --projects gremlin-server -Dtest=AuthorizerTest
+ */
+public class AuthorizerTest {
+
+    final String BYTECODE = "bytecode";
+    final String BYTECODE_LAMBDA = "bytecode-lambda";
+    final String BYTECODE_MUTATE = "bytecode-mutate";
+    final String BYTECODE_OLAP = "bytecode-OLAP";
+    final String BYTECODE_SUBGRAPH = "bytecode-subgraph";
+
+    AllowListAuthorizer authorizer;
+    SubgraphTraversals subgraphTraversals;
+
+    @Rule
+    public TestName name = new TestName();
+
+    @Before
+    public void setup() {
+        final Map<String, Object> config = new HashMap<>();
+        final String yamlName = "org/apache/tinkerpop/gremlin/server/allow-list.yaml";
+        String file = Objects.requireNonNull(getClass().getClassLoader().getResource(yamlName)).getFile();
+        config.put(AllowListAuthorizer.KEY_AUTHORIZATION_ALLOWLIST, file);
+        authorizer = new AllowListAuthorizer();
+        authorizer.setup(config);
+    }
+
+    @Test
+    public void shouldAuthorizeBytecodeRequest() throws AuthorizationException {
+        positiveBytecode("userclassic", "gclassic", BYTECODE);
+        positiveBytecode("usermodern", "gmodern", BYTECODE);
+        positiveBytecode("stephen", "gmodern", BYTECODE);
+        positiveBytecode("userclassic", "gcrew", BYTECODE);
+        positiveBytecode("usermodern", "gcrew", BYTECODE);
+        positiveBytecode("stephen", "gcrew", BYTECODE);
+        positiveBytecode("userclassic", "ggrateful", BYTECODE);
+        positiveBytecode("usersink", "ggrateful", BYTECODE);
+        positiveBytecode("anyuser", "ggrateful", BYTECODE);
+        positiveBytecode("usersandbox", "gclassic", BYTECODE);
+        positiveBytecode("marko", "gcrew", BYTECODE);
+    }
+
+    @Test
+    public void shouldNotAuthorizeBytecodeRequest() {
+        negativeBytecode("usersink", "gclassic", BYTECODE);
+        negativeBytecode("usersink", "gmodern", BYTECODE);
+        negativeBytecode("usersink", "gcrew", BYTECODE);
+        negativeBytecode("anyuser", "gclassic", BYTECODE);
+        negativeBytecode("anyuser", "gmodern", BYTECODE);
+        negativeBytecode("anyuser", "gcrew", BYTECODE);
+    }
+
+    @Test
+    public void shouldAuthorizeLambdaBytecodeRequest() throws AuthorizationException {
+        positiveBytecode("usersandbox", "gclassic", BYTECODE_LAMBDA);
+        positiveBytecode("marko", "gcrew", BYTECODE_LAMBDA);
+    }
+
+    @Test
+    public void shouldNotAuthorizeLambdaBytecodeRequest() {
+        negativeBytecode("userclassic", "gclassic", BYTECODE_LAMBDA);
+        negativeBytecode("usermodern", "gmodern", BYTECODE_LAMBDA);
+        negativeBytecode("stephen", "gmodern", BYTECODE_LAMBDA);
+        negativeBytecode("userclassic", "gcrew", BYTECODE_LAMBDA);
+        negativeBytecode("usermodern", "gcrew", BYTECODE_LAMBDA);
+        negativeBytecode("stephen", "gcrew", BYTECODE_LAMBDA);
+        negativeBytecode("userclassic", "ggrateful", BYTECODE_LAMBDA);
+        negativeBytecode("usersink", "ggrateful", BYTECODE_LAMBDA);
+        negativeBytecode("anyuser", "ggrateful", BYTECODE_LAMBDA);
+    }
+
+    @Test
+    public void shouldAuthorizeMutatingBytecodeRequest() throws AuthorizationException {
+        positiveBytecode("usersandbox", "gclassic", BYTECODE_MUTATE);
+        positiveBytecode("marko", "gcrew", BYTECODE_MUTATE);
+    }
+
+    @Test
+    public void shouldNotAuthorizeMutatingBytecodeRequest() {
+        negativeBytecode("userclassic", "gclassic", BYTECODE_MUTATE);
+        negativeBytecode("usermodern", "gmodern", BYTECODE_MUTATE);
+        negativeBytecode("stephen", "gmodern", BYTECODE_MUTATE);
+        negativeBytecode("userclassic", "gcrew", BYTECODE_MUTATE);
+        negativeBytecode("usermodern", "gcrew", BYTECODE_MUTATE);
+        negativeBytecode("stephen", "gcrew", BYTECODE_MUTATE);
+        negativeBytecode("userclassic", "ggrateful", BYTECODE_MUTATE);
+        negativeBytecode("usersink", "ggrateful", BYTECODE_MUTATE);
+        negativeBytecode("anyuser", "ggrateful", BYTECODE_MUTATE);
+    }
+
+    @Test
+    public void shouldAuthorizeOLAPBytecodeRequest() throws AuthorizationException {
+        positiveBytecode("usersandbox", "gclassic", BYTECODE_OLAP);
+        positiveBytecode("marko", "gcrew", BYTECODE_OLAP);
+    }
+
+    @Test
+    public void shouldNotAuthorizeOLAPBytecodeRequest() {
+        negativeBytecode("userclassic", "gclassic", BYTECODE_OLAP);
+        negativeBytecode("usermodern", "gmodern", BYTECODE_OLAP);
+        negativeBytecode("stephen", "gmodern", BYTECODE_OLAP);
+        negativeBytecode("userclassic", "gcrew", BYTECODE_OLAP);
+        negativeBytecode("usermodern", "gcrew", BYTECODE_OLAP);
+        negativeBytecode("stephen", "gcrew", BYTECODE_OLAP);
+        negativeBytecode("userclassic", "ggrateful", BYTECODE_OLAP);
+        negativeBytecode("usersink", "ggrateful", BYTECODE_OLAP);
+        negativeBytecode("anyuser", "ggrateful", BYTECODE_OLAP);
+    }
+
+    @Test
+    public void shouldAuthorizeSubgraphStrategyBytecodeRequest() throws AuthorizationException {
+        subgraphTraversals = new SubgraphTraversals();
+        positiveBytecode("usersandbox", "gclassic", BYTECODE_SUBGRAPH);
+        positiveBytecode("marko", "gcrew", BYTECODE_SUBGRAPH);
+    }
+
+    @Test
+    public void shouldNotAuthorizeSubgraphStrategyBytecodeRequest() {
+        subgraphTraversals = new SubgraphTraversals();
+        negativeBytecode("userclassic", "gclassic", BYTECODE_SUBGRAPH);
+        negativeBytecode("usermodern", "gmodern", BYTECODE_SUBGRAPH);
+        negativeBytecode("stephen", "gmodern", BYTECODE_SUBGRAPH);
+        negativeBytecode("userclassic", "gcrew", BYTECODE_SUBGRAPH);
+        negativeBytecode("usermodern", "gcrew", BYTECODE_SUBGRAPH);
+        negativeBytecode("stephen", "gcrew", BYTECODE_SUBGRAPH);
+        negativeBytecode("userclassic", "ggrateful", BYTECODE_SUBGRAPH);
+        negativeBytecode("usersink", "ggrateful", BYTECODE_SUBGRAPH);
+        negativeBytecode("anyuser", "ggrateful", BYTECODE_SUBGRAPH);
+    }
+
+    @Test
+    public void shouldAuthorizeStringRequest() throws AuthorizationException {
+        authorizer.authorize(new AuthenticatedUser("usersandbox"), buildRequestMessage("gclassic"));
+        authorizer.authorize(new AuthenticatedUser("marko"), buildRequestMessage("gcrew"));
+    }
+
+    @Test
+    public void shouldNotAuthorizeStringReques() {
+        negativeString("userclassic", "gclassic");
+        negativeString("stephen", "gmodern");
+        negativeString("userclassic", "gmodern");
+        negativeString("usersink", "gclassic");
+        negativeString("anyuser", "ggrateful");
+    }
+
+    private void positiveBytecode(final String username, final String traversalSource, final String requestType) throws AuthorizationException {
+        final Map<String, String> aliases = new HashMap<>();
+        aliases.put("g", traversalSource);
+        authorizer.authorize(new AuthenticatedUser(username), bytecodeRequest(requestType), aliases);
+    }
+
+    private void negativeBytecode(final String username, final String traversalSource, final String requestType) {
+        final Map<String, String> aliases = new HashMap<>();
+        aliases.put("g", traversalSource);
+        final String message;
+        switch (requestType) {
+            case BYTECODE:           message = String.format(REJECT_BYTECODE + ".", "[" + traversalSource + "]"); break;
+            case BYTECODE_LAMBDA:    message = String.format(REJECT_BYTECODE + " using " + REJECT_LAMBDA + ".", "[" + traversalSource + "]"); break;
+            case BYTECODE_MUTATE:    message = String.format(REJECT_BYTECODE + " using " + REJECT_MUTATE + ".", "[" + traversalSource + "]"); break;
+            case BYTECODE_OLAP:      message = String.format(REJECT_BYTECODE + " using " + REJECT_OLAP + ".", "[" + traversalSource + "]"); break;
+            case BYTECODE_SUBGRAPH:  message = String.format(REJECT_BYTECODE + " using " + REJECT_SUBGRAPH + ".", "[" + traversalSource + "]"); break;
+            default: throw new IllegalArgumentException();
+        }
+        try {
+            authorizer.authorize(new AuthenticatedUser(username), bytecodeRequest(requestType), aliases);
+            fail("Test code did not fail while it should have failed!");
+        } catch(AuthorizationException e) {
+            assertEquals(message, e.getMessage());
+        }
+    }
+
+    private Bytecode bytecodeRequest(final String requestType) {
+        final GraphTraversalSource g = TinkerGraph.open().traversal();
+        final Bytecode bytecode;
+
+        switch (requestType) {
+            case BYTECODE:           bytecode = g.V().asAdmin().getBytecode(); break;
+            case BYTECODE_LAMBDA:    bytecode = g.V().map(Lambda.function("it.get()")).asAdmin().getBytecode(); break;
+            case BYTECODE_MUTATE:    bytecode = g.withoutStrategies(ReadOnlyStrategy.class).V().addV().asAdmin().getBytecode(); break;
+            case BYTECODE_OLAP:      bytecode = g.withoutStrategies(VertexProgramRestrictionStrategy.class).withComputer().V().asAdmin().getBytecode(); break;
+            case BYTECODE_SUBGRAPH:  bytecode = subgraphTraversals.get(); break;
+            default: throw new IllegalArgumentException();
+        }
+        return bytecode;
+    }
+
+    private void negativeString(final String username, final String traversalSource) {
+        try {
+            authorizer.authorize(new AuthenticatedUser(username), buildRequestMessage(traversalSource));
+            fail("Test code did not fail while it should have failed!");
+        } catch(AuthorizationException e) {
+            assertEquals(REJECT_STRING, e.getMessage());
+        }
+    }
+
+    private RequestMessage buildRequestMessage(final String traversalSource) {
+        final String script = String.format("1+1; %s.V().map{it.get()}", traversalSource);
+        return RequestMessage.build(Tokens.OPS_EVAL).addArg(Tokens.ARGS_GREMLIN, script).create();
+    }
+
+    private static class SubgraphTraversals implements Supplier<Bytecode> {
+        final GraphTraversalSource g = TinkerGraph.open().traversal();
+        final Iterator<Bytecode> mutatingBytecodes = Arrays.asList(
+                g.withoutStrategies(SubgraphStrategy.class).V().asAdmin().getBytecode(),
+                g.withStrategies(SubgraphStrategy.build().vertices(__.bothE()).create()).V().asAdmin().getBytecode(),
+                g.withoutStrategies(SubgraphStrategy.class).V().asAdmin().getBytecode(),
+                g.withStrategies(SubgraphStrategy.build().vertices(__.bothE()).create()).V().asAdmin().getBytecode(),
+                g.withoutStrategies(SubgraphStrategy.class).V().asAdmin().getBytecode(),
+                g.withStrategies(SubgraphStrategy.build().vertices(__.bothE()).create()).V().asAdmin().getBytecode(),
+                g.withoutStrategies(SubgraphStrategy.class).V().asAdmin().getBytecode(),
+                g.withStrategies(SubgraphStrategy.build().vertices(__.bothE()).create()).V().asAdmin().getBytecode(),
+                g.withoutStrategies(SubgraphStrategy.class).V().asAdmin().getBytecode(),
+                g.withStrategies(SubgraphStrategy.build().vertices(__.bothE()).create()).V().asAdmin().getBytecode(),
+                g.withoutStrategies(SubgraphStrategy.class).V().asAdmin().getBytecode(),
+                g.withStrategies(SubgraphStrategy.build().vertices(__.bothE()).create()).V().asAdmin().getBytecode()
+        ).iterator();
+
+        public Bytecode get() {
+            return mutatingBytecodes.next();
+        }
+    }
+}
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/channel/AbstractGremlinServerChannelizerIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/channel/AbstractGremlinServerChannelizerIntegrateTest.java
index a7ea488..38f2c9a 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/channel/AbstractGremlinServerChannelizerIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/channel/AbstractGremlinServerChannelizerIntegrateTest.java
@@ -22,7 +22,6 @@
 import org.apache.tinkerpop.gremlin.driver.AuthProperties;
 import org.apache.tinkerpop.gremlin.driver.Client;
 import org.apache.tinkerpop.gremlin.driver.Cluster;
-import org.apache.tinkerpop.gremlin.driver.Channelizer;
 import org.apache.tinkerpop.gremlin.server.AbstractGremlinServerIntegrationTest;
 import org.apache.tinkerpop.gremlin.server.Settings;
 import org.apache.tinkerpop.gremlin.server.TestClientFactory;
@@ -62,8 +61,6 @@
     protected static final String WSS = "wss";
     protected static final String WS_AND_HTTP = "wsAndHttp";
     protected static final String WSS_AND_HTTPS = "wssAndHttps";
-    protected static final String NIO = "nio";
-    protected static final String NIO_SECURE = "nioSecure";
 
     public abstract String getProtocol();
     public abstract String getSecureProtocol();
@@ -181,10 +178,7 @@
         private CloseableHttpClient httpClient = null;
         private Cluster wsCluster = null;
         private Cluster.Builder wsBuilder = null;
-        private Cluster nioCluster = null;
-        private Cluster.Builder nioBuilder = null;
         private Client wsClient = null;
-        private Client.ClusteredClient nioClient = null;
         private boolean secure = false;
 
 
@@ -213,13 +207,6 @@
                     secure = true;
                     this.wsBuilder = TestClientFactory.build();
                     break;
-                case NIO:
-                    this.nioBuilder = TestClientFactory.build();
-                    break;
-                case NIO_SECURE:
-                    this.nioBuilder = TestClientFactory.build();
-                    secure = true;
-                    break;
             }
         }
 
@@ -252,9 +239,6 @@
             if (wsCluster != null) {
                 wsCluster.close();
             }
-            if (nioCluster != null) {
-                nioCluster.close();
-            }
         }
 
         public void sendAndAssertUnauthorized(final String gremlin, final String username, final String password) throws Exception {
@@ -273,15 +257,6 @@
                     assertEquals("Username and/or password are incorrect", e.getCause().getMessage());
                 }
             }
-            if (nioBuilder != null) {
-                setNioClient(username, password);
-                try {
-                    nioClient.submit(gremlin);
-                } catch(Exception e) {
-                    assertEquals("Username and/or password are incorrect", e.getCause().getMessage());
-                }
-            }
-
         }
 
         public void sendAndAssert(final String gremlin, final Object result, final String username, final String password) throws Exception {
@@ -299,24 +274,6 @@
                 setWsClient(username, password);
                 assertEquals(result, wsClient.submit(gremlin).all().get().get(0).getInt());
             }
-            if (nioClient != null) {
-                assertEquals(result, nioClient.submit(gremlin).all().get().get(0).getInt());
-            }
-        }
-
-        private void setNioClient(final String username, final String password) {
-            nioBuilder.channelizer(Channelizer.NioChannelizer.class.getName());
-            if (username != null && password != null) {
-                final AuthProperties authProps = new AuthProperties()
-                                                .with(Property.USERNAME, username)
-                                                .with(Property.PASSWORD, password);
-
-                nioCluster = nioBuilder.enableSsl(secure).sslSkipCertValidation(true).authProperties(authProps).create();
-                nioClient = nioCluster.connect();
-            } else {
-                nioCluster = nioBuilder.enableSsl(secure).create();
-                nioClient = nioCluster.connect();
-            }
         }
 
         private void setWsClient(final String username, final String password) {
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/channel/HttpChannelizerIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/channel/HttpChannelizerIntegrateTest.java
index 166764b..f28969c 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/channel/HttpChannelizerIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/channel/HttpChannelizerIntegrateTest.java
@@ -22,6 +22,7 @@
 import org.apache.tinkerpop.gremlin.server.auth.SimpleAuthenticator;
 import org.apache.tinkerpop.gremlin.server.Settings;
 
+import org.apache.tinkerpop.gremlin.server.handler.SaslAndHttpBasicAuthenticationHandler;
 import org.junit.Test;
 import org.junit.Assert;
 
@@ -29,6 +30,9 @@
 import java.util.HashMap;
 import java.net.SocketException;
 
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assume.assumeThat;
+
 public class HttpChannelizerIntegrateTest extends AbstractGremlinServerChannelizerIntegrateTest {
 
     @Override
@@ -74,6 +78,7 @@
         final Settings.AuthenticationSettings authSettings = new Settings.AuthenticationSettings();
         final Map<String,Object> authConfig = new HashMap<>();
         authSettings.authenticator = SimpleAuthenticator.class.getName();
+        authSettings.authenticationHandler = SaslAndHttpBasicAuthenticationHandler.class.getName();
         authConfig.put(SimpleAuthenticator.CONFIG_CREDENTIALS_DB, "conf/tinkergraph-credentials.properties");
         authSettings.config = authConfig;
 
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/channel/NioChannelizerIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/channel/NioChannelizerIntegrateTest.java
deleted file mode 100644
index 8388b40..0000000
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/channel/NioChannelizerIntegrateTest.java
+++ /dev/null
@@ -1,56 +0,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.
- */
-package org.apache.tinkerpop.gremlin.server.channel;
-
-
-import org.apache.tinkerpop.gremlin.server.auth.SimpleAuthenticator;
-import org.apache.tinkerpop.gremlin.server.Settings;
-
-import java.util.Map;
-import java.util.HashMap;
-
-public class NioChannelizerIntegrateTest extends AbstractGremlinServerChannelizerIntegrateTest {
-
-    @Override
-    public String getProtocol() {
-        return NIO;
-    }
-
-    @Override
-    public String getSecureProtocol() {
-        return NIO_SECURE;
-    }
-
-    @Override
-    public String getChannelizer() {
-        return NioChannelizer.class.getName();
-    }
-
-    @Override
-    public Settings.AuthenticationSettings getAuthSettings() {
-        final Settings.AuthenticationSettings authSettings = new Settings.AuthenticationSettings();
-        final Map<String,Object> authConfig = new HashMap<>();
-        authSettings.authenticator = SimpleAuthenticator.class.getName();
-        authConfig.put(SimpleAuthenticator.CONFIG_CREDENTIALS_DB, "conf/tinkergraph-credentials.properties");
-        authSettings.config = authConfig;
-
-        return authSettings;
-    }
-
-}
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/channel/UnifiedChannelizerIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/channel/UnifiedChannelizerIntegrateTest.java
new file mode 100644
index 0000000..a090a20
--- /dev/null
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/channel/UnifiedChannelizerIntegrateTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.server.channel;
+
+import org.apache.tinkerpop.gremlin.server.Settings;
+import org.apache.tinkerpop.gremlin.server.auth.SimpleAuthenticator;
+import org.apache.tinkerpop.gremlin.server.handler.SaslAndHttpBasicAuthenticationHandler;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class UnifiedChannelizerIntegrateTest extends AbstractGremlinServerChannelizerIntegrateTest {
+
+    @Override
+    public String getProtocol() {
+        return WS_AND_HTTP;
+    }
+
+    @Override
+    public String getSecureProtocol() {
+        return WSS_AND_HTTPS;
+    }
+
+    @Override
+    public String getChannelizer() {
+        return UnifiedChannelizer.class.getName();
+    }
+
+    @Override
+    public Settings.AuthenticationSettings getAuthSettings() {
+        final Settings.AuthenticationSettings authSettings = new Settings.AuthenticationSettings();
+        final Map<String,Object> authConfig = new HashMap<>();
+        authSettings.authenticator = SimpleAuthenticator.class.getName();
+        authSettings.authenticationHandler = SaslAndHttpBasicAuthenticationHandler.class.getName();
+        authConfig.put(SimpleAuthenticator.CONFIG_CREDENTIALS_DB, "conf/tinkergraph-credentials.properties");
+        authSettings.config = authConfig;
+
+        return authSettings;
+    }
+
+}
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/op/AbstractEvalOpProcessorTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/op/AbstractEvalOpProcessorTest.java
index 485a74d..aa3fd73 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/op/AbstractEvalOpProcessorTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/op/AbstractEvalOpProcessorTest.java
@@ -19,6 +19,7 @@
 package org.apache.tinkerpop.gremlin.server.op;
 
 import io.netty.channel.ChannelHandlerContext;
+import org.apache.tinkerpop.gremlin.driver.Tokens;
 import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
@@ -36,7 +37,7 @@
 import java.util.concurrent.CompletableFuture;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.mockito.Matchers.anyString;
 
 public class AbstractEvalOpProcessorTest {
@@ -44,7 +45,9 @@
     @Test
     public void evalOpInternalShouldHandleAllEvaluationExceptions() throws OpProcessorException {
         final AbstractEvalOpProcessor processor = new StandardOpProcessor();
-        final RequestMessage request = RequestMessage.build("test").create();
+        final RequestMessage request = RequestMessage.build("test").
+                addArg(Tokens.ARGS_LANGUAGE, "gremlin-groovy").
+                addArg(Tokens.ARGS_GREMLIN, "1+1").create();
         final Settings settings = new Settings();
         final ChannelHandlerContext ctx = Mockito.mock(ChannelHandlerContext.class);
         final ArgumentCaptor<ResponseMessage> responseCaptor = ArgumentCaptor.forClass(ResponseMessage.class);
@@ -60,7 +63,7 @@
         processor.evalOpInternal(contextspy, contextspy::getGremlinExecutor, SimpleBindings::new);
 
         Mockito.verify(contextspy, Mockito.times(1)).writeAndFlush(responseCaptor.capture());
-        assertEquals(ResponseStatusCode.SERVER_ERROR_SCRIPT_EVALUATION, responseCaptor.getValue().getStatus().getCode());
+        assertEquals(ResponseStatusCode.SERVER_ERROR_EVALUATION, responseCaptor.getValue().getStatus().getCode());
         assertEquals(request.getRequestId(), responseCaptor.getValue().getRequestId());
         assertThat(responseCaptor.getValue().getStatus().getMessage(), CoreMatchers.containsString("test-exception"));
     }
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/util/Log4jRecordingAppenderTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/util/Log4jRecordingAppenderTest.java
index 7e3b0c8..05cb437 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/util/Log4jRecordingAppenderTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/util/Log4jRecordingAppenderTest.java
@@ -27,7 +27,7 @@
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 
 /**
  * @author Stephen Mallette (http://stephen.genoprime.com)
diff --git a/gremlin-server/src/test/resources/client.crt b/gremlin-server/src/test/resources/client.crt
deleted file mode 100644
index 297335b..0000000
--- a/gremlin-server/src/test/resources/client.crt
+++ /dev/null
@@ -1,40 +0,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.
- */
-
------BEGIN CERTIFICATE-----
-MIIDajCCAlICCQCG0QGj7JgLvTANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJV
-UzELMAkGA1UECAwCTkMxEDAOBgNVBAcMB1JhbGVpZ2gxEzARBgNVBAoMCkNsaWVu
-dCBBcHAxDzANBgNVBAMMBmNsaWVudDEiMCAGCSqGSIb3DQEJARYTZ3JlbWxpbi11
-c2VyQGNsaWVudDAgFw0xNzAxMjMxODQzMjNaGA8yMTE2MTIzMDE4NDMyM1owdjEL
-MAkGA1UEBhMCVVMxCzAJBgNVBAgMAk5DMRAwDgYDVQQHDAdSYWxlaWdoMRMwEQYD
-VQQKDApDbGllbnQgQXBwMQ8wDQYDVQQDDAZjbGllbnQxIjAgBgkqhkiG9w0BCQEW
-E2dyZW1saW4tdXNlckBjbGllbnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
-AoIBAQDU7U5tNN+0HCKZX31ZKMZwAUI7qGCpYXd05z5SKRWesNsrEeCLnu1DgYhL
-j+hSi2LI+RwTF45DH8zEPIzQ6HEMzuCd2uy7bdDrXv6H/tFUx9Iw0ea5oXGX1qNa
-tzjPTSmw22VXbSo+B5EG0coC5oDy9SpYb2HxeDmegI2OZL6ROFPKbCUTzyJfqTpy
-1mdgnnKTVuQdtWvj/sXDAZzRqtFHwBkHezKCOC4yLNi5+pI01+0V7FbtyCqH7iPS
-VS9VKsLuhPkzAkRh/x9CxaSrwicyzyB3Kyfg7kjmtdrUOrfgxdw+MMPog3JrGoLr
-tfvc9LUh0ImpLPngyWhwc5iNGwmLAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAEi0
-IVUIbDuirNivJXXXT5eFUgfAx5iPjbR1XBjCuHO061d0B8itU7cidKs0y5mDoauy
-vuywNBih6FAsHoYLrqI1gt65fybGxq3wlhnqdLH7GDeHw65e2PB2x+M4NtQlkPTq
-dUgUtQzAo8Hc4DNR5BrvCtLjqT7Knq8QHtGLys8eoDur09894+6WeUjrgUTp88Jl
-uqrZqRHvdMW7sge73cpU1dsDJW0rJqCLZ+qA2V+ZRRCQY1oHuHeK6Dkokabaq3rr
-WrpxfppIPCusJx4nnIwu4d0gZwAKwabOS8lJPjV0frRkA0BuAEpMIbOwZ10Tw7ZM
-2HzamAOiiks4NFDSs94=
------END CERTIFICATE-----
diff --git a/gremlin-server/src/test/resources/client.key.pk8 b/gremlin-server/src/test/resources/client.key.pk8
deleted file mode 100644
index 213cce3..0000000
--- a/gremlin-server/src/test/resources/client.key.pk8
+++ /dev/null
@@ -1,47 +0,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.
- */
------BEGIN ENCRYPTED PRIVATE KEY-----
-MIIE6TAbBgkqhkiG9w0BBQMwDgQIuH3rVXHniaECAggABIIEyDzHWny/fttnN6ze
-Q/iNE1z72HBg2anTK3gHdu8W3F9W6BSLhuKaUumxcxX6IfkZmxinqwUxSNrRBswr
-s71EZ7QmX2eaeiWxlo6zP0I898fzqvSBWk6NhntV1SVG++/CMeIMZARs85OxcNGN
-fKEXtBUf5jlo+hy9bVgQRO2M1vHzek/deOHyj1eXwEi2Oxcw1ly3o9lRayIFJFou
-0olp58h8pD5qOsSfIrNG6bHBg00eP1ILE1FUPCdOfDrQEjiKKVqllCXdsUz/KjBY
-0iGYMw3aT2LELnibTy0alFswGaDBRqlzGSIGrejdGTOBj7NmeiW2yOY+aUjCkdXw
-ll862oItlJZO/B16EGgI+czdXZgcL5YRGVOu6loOlGxU60Y681Acjn9wdlxxOqXa
-te7khLGX6qm3ceMJ2DQbMO8JS6UBsGjZqq/ictwfGxNDiTeiWmoyrQvO3qkaqsEt
-iLBJdSsogzxx+hfj+xiBRorf9Gvkk6hDnzeuZl9Voak5qY7RrcmxD8ecdh3g2faO
-VFtxTAxmHJakgGF7fZ7jQoxZJzzRn+rjIhATaEH1/MMME77Z+8rkE74oxFOrizDU
-Eb4AMUV/xgrAtQLGpIFALL7oPk2r1exFgywL40q5/BcXCx65eliXtyoBIc5X+t90
-fTB8lA3K5mT2MXzwMyMPv2n8d8Ta2OjisRHjSue6AqNqifBuniVfSpHP9OUlsKaL
-u3eN8mSuPDhlo7RGG8+B7mSqGDjORR/+BJvwgFreIyurOL22g887uPwjzPXs6lll
-3VFclsrfEqNMP6kBsXlHNAxjT10WoWrF+ONPEyg9PrzTGryTRqW+ptzBqtiQrVag
-/KMee3sdg6i9GN+EGc43DNJzxxlFXvT9kBvOk66tOPEE5963k3ZikjuAX7xBVOvM
-AlqzHHW727fHXqYp0yabWTpr72RuUGQOqPZiMsWd6x65HL2I0WHP9PXTf1vMmnj3
-NgiN1paATl5L8S9Jt8WL8iLskVt2f+CAKJuQfamY5Fg54m/cJzNHV8nAMTTl+0EN
-9vUhvn672wZd9JfB4PMtrIhYFNJElJmmdAwjFrop6goXA/UGgf3M4QNiQetFGxWP
-aJ0tMSdA/ax9nGA5LU6iCwPe51ExrQJAVFw+oE3I8+J1oz1fQOl8zIgyOFwG+bJx
-/Y/JyraEssZ5RLtaGgcm9vZm8Wo8a5TQCbqhoY8x7MwyF7/VpbRZ3bGEUFnWd/yF
-1tCPeZ+q5HN79P3qfZzAcFAU3z3HawXDwQ3XO3Plix04Vjr+QFENeJxhL+3FXtLx
-4nF+Y9Fq6I5x8YQLrPYkIyRz8xWxVBQFZTeNhWx5nYWNcDXgz/S8v3ipY+EPEj9Q
-uOQWNdSJ9XOR+Ju/KSP0151guLkUwpHBCi/CFY4TgD6iFglTyLuZpW2bbim1mmDI
-LSDHwrERQWNmcNznK4PIw227w6EZqUEI0jjkANhXQG6dz1VkaTIZAoEVWHhFNi8S
-gSPkhsWN822QzxZQb+74JoUFBTifP50giaCd6p2HKw8U20FAPyseVIY3IsYatuLU
-8VhfeBQ1GLOOy8/5mRyjL+Gjn/OfNPwps9uuOogx/jGf0JhtjAEY2WNoEEB9DkUv
-AijT0ck1+DM3by4MlA==
------END ENCRYPTED PRIVATE KEY-----
diff --git a/gremlin-server/src/test/resources/log4j-test.properties b/gremlin-server/src/test/resources/log4j-test.properties
index a9aeddd..4485712 100644
--- a/gremlin-server/src/test/resources/log4j-test.properties
+++ b/gremlin-server/src/test/resources/log4j-test.properties
@@ -20,5 +20,9 @@
 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
 log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n
 
+log4j.logger.org.apache.tinkerpop.gremlin.server.AbstractChannelizer=ERROR
+log4j.logger.org.apache.tinkerpop.gremlin.server.AbstractGremlinServerIntegrationTest=INFO
 log4j.logger.org.apache.tinkerpop.gremlin.server.op.AbstractEvalOpProcessor=ERROR
+log4j.logger.org.apache.tinkerpop.gremlin.server.handler.MultiTaskSession=ERROR
+log4j.logger.org.apache.tinkerpop.gremlin.server.handler.SingleTaskSession=ERROR
 log4j.logger.audit.org.apache.tinkerpop.gremlin.server=INFO
diff --git a/gremlin-server/src/test/resources/org/apache/tinkerpop/gremlin/server/allow-list-http-anonymous.yaml b/gremlin-server/src/test/resources/org/apache/tinkerpop/gremlin/server/allow-list-http-anonymous.yaml
new file mode 100644
index 0000000..a4e776b
--- /dev/null
+++ b/gremlin-server/src/test/resources/org/apache/tinkerpop/gremlin/server/allow-list-http-anonymous.yaml
@@ -0,0 +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
+#
+# 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.
+
+grants: {
+  sandbox: [groupsandbox]
+}
+
+groups: {
+  groupsandbox: [anonymous]
+}
diff --git a/gremlin-server/src/test/resources/org/apache/tinkerpop/gremlin/server/allow-list.yaml b/gremlin-server/src/test/resources/org/apache/tinkerpop/gremlin/server/allow-list.yaml
new file mode 100644
index 0000000..7654952
--- /dev/null
+++ b/gremlin-server/src/test/resources/org/apache/tinkerpop/gremlin/server/allow-list.yaml
@@ -0,0 +1,32 @@
+# 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.
+
+grants: {
+  gclassic: [groupclassic],
+  gmodern: [groupmodern],
+  gcrew: [groupclassic, groupmodern],
+  ggrateful: [groupgrateful],
+  sandbox: [groupsandbox]
+}
+
+groups: {
+  groupclassic: [userclassic],
+  groupmodern: [usermodern, stephen],
+  groupsink: [usersink],
+  groupgrateful: [anonymous],
+  groupsandbox: [usersandbox, marko]
+}
diff --git a/gremlin-server/src/test/resources/org/apache/tinkerpop/gremlin/server/gremlin-server-integration.yaml b/gremlin-server/src/test/resources/org/apache/tinkerpop/gremlin/server/gremlin-server-integration.yaml
index 601e404..35a19d7 100644
--- a/gremlin-server/src/test/resources/org/apache/tinkerpop/gremlin/server/gremlin-server-integration.yaml
+++ b/gremlin-server/src/test/resources/org/apache/tinkerpop/gremlin/server/gremlin-server-integration.yaml
@@ -21,6 +21,7 @@
 # Changes to this file need to be appropriately replicated to
 #
 # - docker/gremlin-server/gremlin-server-integration.yaml
+# - docker/gremlin-server/gremlin-server-integration-krb5.yaml
 # - docker/gremlin-server/gremlin-server-integration-secure.yaml
 #
 # Without such changes, the test docker server can't be started for independent
@@ -61,6 +62,7 @@
   - { className: org.apache.tinkerpop.gremlin.server.op.standard.StandardOpProcessor, config: {}}
 metrics: {
   slf4jReporter: {enabled: true, interval: 180000}}
+gremlinPool: 8
 strictTransactionManagement: false
 idleConnectionTimeout: 0
 keepAliveInterval: 0
diff --git a/gremlin-server/src/test/resources/server.crt b/gremlin-server/src/test/resources/server.crt
deleted file mode 100644
index b777e34..0000000
--- a/gremlin-server/src/test/resources/server.crt
+++ /dev/null
@@ -1,41 +0,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.
- */
-
------BEGIN CERTIFICATE-----
-MIIDrjCCApYCCQCg8hxjInTcQzANBgkqhkiG9w0BAQsFADCBlzELMAkGA1UEBhMC
-VVMxCzAJBgNVBAgMAkNBMRQwEgYDVQQHDAtTYW50YSBDbGFyYTEZMBcGA1UECgwQ
-QXBhY2hlIFRpbmtlclBvcDEQMA4GA1UECwwHR3JlbWxpbjESMBAGA1UEAwwJbG9j
-YWxob3N0MSQwIgYJKoZIhvcNAQkBFhVzcG1hbGxldHRlQGFwYWNoZS5vcmcwIBcN
-MTcwMTIzMTg0MTEwWhgPMjExNjEyMzAxODQxMTBaMIGXMQswCQYDVQQGEwJVUzEL
-MAkGA1UECAwCQ0ExFDASBgNVBAcMC1NhbnRhIENsYXJhMRkwFwYDVQQKDBBBcGFj
-aGUgVGlua2VyUG9wMRAwDgYDVQQLDAdHcmVtbGluMRIwEAYDVQQDDAlsb2NhbGhv
-c3QxJDAiBgkqhkiG9w0BCQEWFXNwbWFsbGV0dGVAYXBhY2hlLm9yZzCCASIwDQYJ
-KoZIhvcNAQEBBQADggEPADCCAQoCggEBAK5l+5DDrSGq1n1vYIMbb95buWlo4u5s
-V8wHNmeFCuqNvGfxermHS88SSy6qvdSXISfe+kj9Jkfn1Pjx4czwcnF/q4Au3Gc6
-T9MiAKJUfb4+MwPKERacFobk6LTreKpzvXymAhhM1ktvvA7/opZ+nENDEoIJK/KS
-CY9vRWeHqI1Q+Rf5Nrqw8eySq/ZhPDlppsu5sQr1ghSsuzXhpYNhq8VBMsysL2Zi
-VF5DFMqg9yhBkxrqo70W/pjo4kQJ/iF/4d/3HHicSCVq3/NCkWMVg0HeOZ1eVaZ/
-D6EXv8cYwyaRmf7SldE7RtdbAU0M+Y0Lmuoi2evls0Oiqf8uxEDXeLUCAwEAATAN
-BgkqhkiG9w0BAQsFAAOCAQEAJFAAUxYeUbf6tAGEKCXISted10TybPW/qCxOXEPN
-TTO+xvnzksbcbzOc2X0N+yYIKtkfiuWgD9UJ4QnLSeEKmouMbkTk0ToYJj7SrviI
-f+9R1IiZMiwz+n0igETkEGOK0Ql26Z4g3kc1IueSD07QOLASTvVLtEyoya7LD4S6
-jk1LnbpbHVmgHY4kmtsg6lVQ1zkqrsDQg9goh8dI5AlNCudpd8zLxzsPbm+Q2+DC
-Wd4A2lKdh3rbY2LYpbVhBj9c6E0laaqgyGC7s37XfmyBp4wYlX/30p6RpCR2rcRW
-SKh5NXN52Xx3WuiP42wm9ZC/de8gaODrW8n44xlEaMPJ3A==
------END CERTIFICATE-----
diff --git a/gremlin-server/src/test/resources/server.key.pk8 b/gremlin-server/src/test/resources/server.key.pk8
deleted file mode 100644
index 9dc6720..0000000
--- a/gremlin-server/src/test/resources/server.key.pk8
+++ /dev/null
@@ -1,47 +0,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.
- */
------BEGIN ENCRYPTED PRIVATE KEY-----
-MIIE6TAbBgkqhkiG9w0BBQMwDgQIJi2M3dPcx+cCAggABIIEyG/0PwTaqm3ekGkn
-8daHjfcqxCpvwOku0pCCgV7AMsrsj4TvMOHOkId+xKVs4AlXV2grPfTQoMrIFFp0
-26hzpZOHEjAe9XbtzVWgphwLVeWOr5ugovyXPxdCqMBrn251y9Yg6csh5pPrsHEp
-RLTZPQPvEVIhA0tRkPPag5BSlj//nH7PnXYRm4VSRg7WQS15ieHsC1xDM9zYni/b
-ffU++twOGvCdvtGd/lqjJj3dPomKynb6Y4cEc73vQ6cQjeXN1W1Nil4QsDZ53H3U
-KvoWuEVYDf1WDFySgHMFgePHXMMWA8ZkgS6rOrV1TDnoZIhG5BSe7aJNJQdVVMub
-NAxZB4C1unIICuAtsP9IEAhevbfNGySi0jbrnun0pTD22Q95HZVycl1YWamrr1Hl
-17TmHQT7zh4GLlXVI3L/FevoswbuR7misyqE3ketNpxdLcHKs82MVLCwbLzuqm60
-tpSm/jrexhNErKU28kdPzWCwruEHdrlOuMSS8N2YgSZxHIjEId8pZED8dsnPvqhe
-CAEa3F68Js9sngeMvThYirpr0wOsSGmGCDrXTmQvTw+q8C+DJLWpjfpKZA4g624f
-E3CUojwOaPrmaEa25eYm0oYDstY8QncG7nBAuljeXWBYfxARYcLI/bLC/M/q+UeS
-gzjQgoacH4r2Y7rwEA0aeYC+9TWn5rPHPWegdc01A2e7OlYKrlu9C1aKZr//GyBM
-lEVRc0u8RL+RVhmp7ftRyATDG9kJR+zDT26hewaEa5atnPKLjf+37hu7a/6GI+2X
-dpWTzmvWal4eEkFuBg2ekl1lCsuuCUBDWyYrlhsWPYTOSKJ/PTuLq7HVqdGB9kEw
-SavnXV5LPOaY4nAzJTdRk9DHdxSwSrjZ5rvMMD1CAbob/GA9t8aYaGcAWtTwMFs4
-sps40mmab3X0LLvTblHtmRCHWswcACbH2DC6H+0awsaZNI80GxSSutKN+2vH3N0C
-6fLwP1VaYm0qPA3pI1vp9Xu5I//6Hzt3aT/R+6KhS+CH3qbJiHNzg1ywdNqgD3Pp
-bJNEiDKWdLd65bvclVVyWHovWIvvEly1TWUsp4YbdrT5asL/VV82fvo4wCttOq96
-msk9OL5vQADJ32D7vnnYadiT2tpJMjNSug7JKHutJ/cJmm8qkqNwFm/BH+w2t7kh
-elbG0f2P7FpPXVMCJPHhmI/+OBECqBHAAWgRRn91GqeGgY+Xy05orL2R/qeNdBbT
-qmrxqm7LesPgo0IqU82quTkiBERaXMu8qUYaYPGVJIskQuWqd/aArhaFmqZhK3bz
-lepJMDAaeaBT/3ULICHdhsSVAhl6iwid40ow8x1cRFoPEljZ9t6fERN1h2ptNyZT
-LRJ4DUXy4RWTHl3+AVyzwcgMpxkxRTzdjguzAjceOHEMm7UNCvSVhFHVBkG6kXXw
-940iYvhkRnn6HRcPbP5xeJp6GX8RoAl42giRO6OGnkhkepOuAcFKJCC2N5OgdKmq
-mlVGEKndriwyzyiPN8noEJksenL1iMSA7HSnM34uCJoEetTBRuv8+721bTdz8dy0
-s/GghsYztugLjho4yivn2fcxw4gMFiSiliyrfbocJnHAubDMZwEu0fpfY+0fBi9+
-e/Odgw8aTlMUKSo+UA==
------END ENCRYPTED PRIVATE KEY-----
diff --git a/gremlin-server/src/test/scripts/generate-all.groovy b/gremlin-server/src/test/scripts/generate-all.groovy
index f6d52a4..f49351b 100644
--- a/gremlin-server/src/test/scripts/generate-all.groovy
+++ b/gremlin-server/src/test/scripts/generate-all.groovy
@@ -59,13 +59,6 @@
   }
 ] as LifeCycleHook]
 
-// discovered that unless the GraphTraversalSource.metaclass gets a method added to it
-// directly in this script then all the metaprogramming done in GremlinLoader will
-// simply be ignored and the following lines will fail. however, this situation only
-// applies when this init script for Gremlin Server is executed by way of the
-// gmavenplus-plugin. normal starts of Gremlin Server do not see this problem. spooky!
-GraphTraversalSource.metaClass.hack << { return null }
-
 // add default TraversalSource instances for each graph instance
 globals << [gclassic : traversal().withEmbedded(classic).withStrategies(ReferenceElementStrategy)]
 globals << [gmodern : traversal().withEmbedded(modern).withStrategies(ReferenceElementStrategy)]
diff --git a/gremlin-server/src/test/scripts/test-server-start.groovy b/gremlin-server/src/test/scripts/test-server-start.groovy
index 398805e..ca59745 100644
--- a/gremlin-server/src/test/scripts/test-server-start.groovy
+++ b/gremlin-server/src/test/scripts/test-server-start.groovy
@@ -18,6 +18,7 @@
  */
 
 import org.apache.tinkerpop.gremlin.server.GremlinServer
+import org.apache.tinkerpop.gremlin.server.KdcFixture
 import org.apache.tinkerpop.gremlin.server.Settings
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -25,8 +26,8 @@
 ////////////////////////////////////////////////////////////////////////////////
 // Changes to this file need to be appropriately replicated to
 //
-// - docker/gremlin-server/gremlin-server-integration.yaml
-// - docker/gremlin-server/gremlin-server-integration-secure.yaml
+// - docker/gremlin-server/*
+// - docker/gremlin-server.sh
 //
 // Without such changes, the test docker server can't be started for independent
 // testing with Gremlin Language Variants.
@@ -43,17 +44,14 @@
 settings.graphs.grateful = gremlinServerDir + "/src/test/scripts/tinkergraph-empty.properties"
 settings.graphs.sink = gremlinServerDir + "/src/test/scripts/tinkergraph-empty.properties"
 settings.scriptEngines["gremlin-groovy"].plugins["org.apache.tinkerpop.gremlin.jsr223.ScriptFileGremlinPlugin"].files = [gremlinServerDir + "/src/test/scripts/generate-all.groovy"]
-if (Boolean.parseBoolean(python)) {
-    settings.scriptEngines["gremlin-python"] = new Settings.ScriptEngineSettings()
-    settings.scriptEngines["gremlin-jython"] = new Settings.ScriptEngineSettings()
-}
 settings.port = 45940
 
 def server = new GremlinServer(settings)
 server.start().join()
 
 project.setContextValue("gremlin.server", server)
-log.info("Gremlin Server with no authentication started on port 45940")
+log.info("Gremlin Server without authentication started on port 45940")
+
 
 def securePropsFile = new File("${projectBaseDir}/target/tinkergraph-credentials.properties")
 if (!securePropsFile.exists()) {
@@ -72,10 +70,6 @@
 settingsSecure.graphs.grateful = gremlinServerDir + "/src/test/scripts/tinkergraph-empty.properties"
 settingsSecure.graphs.sink = gremlinServerDir + "/src/test/scripts/tinkergraph-empty.properties"
 settingsSecure.scriptEngines["gremlin-groovy"].plugins["org.apache.tinkerpop.gremlin.jsr223.ScriptFileGremlinPlugin"].files = [gremlinServerDir + "/src/test/scripts/generate-all.groovy"]
-if (Boolean.parseBoolean(python)) {
-    settingsSecure.scriptEngines["gremlin-python"] = new Settings.ScriptEngineSettings()
-    settingsSecure.scriptEngines["gremlin-jython"] = new Settings.ScriptEngineSettings()
-}
 settingsSecure.port = 45941
 settingsSecure.authentication.authenticator = "org.apache.tinkerpop.gremlin.server.auth.SimpleAuthenticator"
 settingsSecure.authentication.config = [credentialsDb: projectBaseDir + "/target/tinkergraph-credentials.properties"]
@@ -89,4 +83,31 @@
 serverSecure.start().join()
 
 project.setContextValue("gremlin.server.secure", serverSecure)
-log.info("Gremlin Server with authentication started on port 45941")
\ No newline at end of file
+log.info("Gremlin Server with password authentication started on port 45941")
+
+
+def kdcServer = new KdcFixture(projectBaseDir)
+kdcServer.setUp()
+
+project.setContextValue("gremlin.server.kdcserver", kdcServer)
+log.info("KDC started with configuration ${projectBaseDir}/target/kdc/krb5.conf")
+
+def settingsKrb5 = Settings.read("${settingsFile}")
+settingsKrb5.graphs.graph = gremlinServerDir + "/src/test/scripts/tinkergraph-empty.properties"
+settingsKrb5.graphs.classic = gremlinServerDir + "/src/test/scripts/tinkergraph-empty.properties"
+settingsKrb5.graphs.modern = gremlinServerDir + "/src/test/scripts/tinkergraph-empty.properties"
+settingsKrb5.graphs.crew = gremlinServerDir + "/src/test/scripts/tinkergraph-empty.properties"
+settingsKrb5.graphs.grateful = gremlinServerDir + "/src/test/scripts/tinkergraph-empty.properties"
+settingsKrb5.graphs.sink = gremlinServerDir + "/src/test/scripts/tinkergraph-empty.properties"
+settingsKrb5.scriptEngines["gremlin-groovy"].plugins["org.apache.tinkerpop.gremlin.jsr223.ScriptFileGremlinPlugin"].files = [gremlinServerDir + "/src/test/scripts/generate-all.groovy"]
+settingsKrb5.port = 45942
+settingsKrb5.authentication.authenticator = "org.apache.tinkerpop.gremlin.server.auth.Krb5Authenticator"
+settingsKrb5.authentication.config = [
+        "principal": kdcServer.serverPrincipal,
+        "keytab": kdcServer.serviceKeytabFile.getAbsolutePath()]
+
+def serverKrb5 = new GremlinServer(settingsKrb5)
+serverKrb5.start().join()
+
+project.setContextValue("gremlin.server.krb5", serverKrb5)
+log.info("Gremlin Server with kerberos authentication started on port 45942")
diff --git a/gremlin-server/src/test/scripts/test-server-stop.groovy b/gremlin-server/src/test/scripts/test-server-stop.groovy
index 595d9bd..d9fc629 100644
--- a/gremlin-server/src/test/scripts/test-server-stop.groovy
+++ b/gremlin-server/src/test/scripts/test-server-stop.groovy
@@ -29,4 +29,12 @@
 log.info("Shutting down $serverSecure")
 serverSecure.stop().join()
 
+def kdcServer = project.getContextValue("gremlin.server.kdcserver")
+log.info("Shutting down $kdcServer")
+kdcServer.close()
+
+def serverKrb5 = project.getContextValue("gremlin.server.krb5")
+log.info("Shutting down $serverKrb5")
+serverKrb5.stop().join()
+
 log.info("All Gremlin Server instances are shutdown for ${executionName}")
\ No newline at end of file
diff --git a/gremlin-shaded/pom.xml b/gremlin-shaded/pom.xml
index 195dc99..93f93a3 100644
--- a/gremlin-shaded/pom.xml
+++ b/gremlin-shaded/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>org.apache.tinkerpop</groupId>
         <artifactId>tinkerpop</artifactId>
-        <version>3.4.12-SNAPSHOT</version>
+        <version>3.5.1-SNAPSHOT</version>
     </parent>
     <artifactId>gremlin-shaded</artifactId>
     <name>Apache TinkerPop :: Gremlin Shaded</name>
@@ -43,7 +43,6 @@
         <dependency>
             <groupId>org.objenesis</groupId>
             <artifactId>objenesis</artifactId>
-            <version>2.1</version>
             <optional>true</optional>
         </dependency>
         <dependency>
diff --git a/gremlin-test/features/branch/Branch.feature b/gremlin-test/features/branch/Branch.feature
index e160fc8..c8a5b42 100644
--- a/gremlin-test/features/branch/Branch.feature
+++ b/gremlin-test/features/branch/Branch.feature
@@ -42,13 +42,15 @@
 
   Scenario: g_V_branchXlabel_isXpersonX_countX_optionX1__ageX_optionX0__langX_optionX0__nameX
     Given the modern graph
+    And using the parameter xx1 defined as "d[1].l"
+    And using the parameter xx2 defined as "d[0].l"
     And the traversal of
       """
       g.V().
         branch(__.label().is("person").count()).
-          option(1L, __.values("age")).
-          option(0L, __.values("lang")).
-          option(0L, __.values("name"))
+          option(xx1, __.values("age")).
+          option(xx2, __.values("lang")).
+          option(xx2, __.values("name"))
       """
     When iterated to list
     Then the result should be unordered
@@ -64,13 +66,15 @@
 
   Scenario: g_V_branchXlabel_isXpersonX_countX_optionX1__ageX_optionX0__langX_optionX0__nameX_optionXany__labelX
     Given the modern graph
+    And using the parameter xx1 defined as "d[1].l"
+    And using the parameter xx2 defined as "d[0].l"
     And the traversal of
       """
       g.V().
         branch(__.label().is("person").count()).
-          option(1L, __.values("age")).
-          option(0L, __.values("lang")).
-          option(0L, __.values("name")).
+          option(xx1, __.values("age")).
+          option(xx2, __.values("lang")).
+          option(xx2, __.values("name")).
           option(Pick.any, __.label())
       """
     When iterated to list
diff --git a/gremlin-test/features/branch/Choose.feature b/gremlin-test/features/branch/Choose.feature
index 7bb8c03..fdd98c4 100644
--- a/gremlin-test/features/branch/Choose.feature
+++ b/gremlin-test/features/branch/Choose.feature
@@ -19,11 +19,13 @@
 
   Scenario: g_V_chooseXout_countX_optionX2L_nameX_optionX3L_ageX
     Given the modern graph
+    And using the parameter xx1 defined as "d[2].l"
+    And using the parameter xx2 defined as "d[3].l"
     And the traversal of
       """
       g.V().choose(__.out().count()).
-        option(2L, __.values("name")).
-        option(3L, __.values("age"))
+        option(xx1, __.values("name")).
+        option(xx2, __.values("age"))
       """
     When iterated to list
     Then the result should be unordered
@@ -33,10 +35,10 @@
 
   Scenario: g_V_chooseXlabel_eqXpersonX__outXknowsX__inXcreatedXX_name
     Given the modern graph
-    And using the parameter l1 defined as "c[it.label() == 'person']"
+    And using the parameter pred1 defined as "c[it.label() == 'person']"
     And the traversal of
       """
-      g.V().choose(l1, __.out("knows"), __.in("created")).values("name")
+      g.V().choose(pred1, __.out("knows"), __.in("created")).values("name")
       """
     When iterated to list
     Then the result should be unordered
@@ -125,11 +127,11 @@
 
   Scenario: g_V_hasLabelXpersonX_chooseXageX__optionX27L__constantXyoungXX_optionXnone__constantXoldXX_groupCount
     Given the modern graph
-    And using the parameter d27 defined as "d[27].l"
+    And using the parameter xx1 defined as "d[27].l"
     And the traversal of
       """
       g.V().hasLabel("person").choose(__.values("age")).
-          option(d27, __.constant("young")).
+          option(xx1, __.constant("young")).
           option(Pick.none, __.constant("old")).
         groupCount()
       """
@@ -140,11 +142,11 @@
 
   Scenario: g_injectX1X_chooseXisX1X__constantX10Xfold__foldX
     Given the empty graph
-    And using the parameter d10 defined as "d[10].i"
-    And using the parameter d1 defined as "d[1].i"
+    And using the parameter xx1 defined as "d[10].i"
+    And using the parameter xx2 defined as "d[1].i"
     And the traversal of
       """
-      g.inject(d1).choose(__.is(d1), __.constant(d10).fold(), __.fold())
+      g.inject(xx2).choose(__.is(xx2), __.constant(xx1).fold(), __.fold())
       """
     When iterated to list
     Then the result should be unordered
@@ -153,12 +155,12 @@
 
   Scenario: g_injectX2X_chooseXisX1X__constantX10Xfold__foldX
     Given the empty graph
-    And using the parameter d10 defined as "d[10].i"
-    And using the parameter d1 defined as "d[1].i"
-    And using the parameter d2 defined as "d[2].i"
+    And using the parameter xx1 defined as "d[10].i"
+    And using the parameter xx2 defined as "d[1].i"
+    And using the parameter xx3 defined as "d[2].i"
     And the traversal of
       """
-      g.inject(d2).choose(__.is(d1), __.constant(d10).fold(), __.fold())
+      g.inject(xx3).choose(__.is(xx2), __.constant(xx1).fold(), __.fold())
       """
     When iterated to list
     Then the result should be unordered
diff --git a/gremlin-test/features/branch/Local.feature b/gremlin-test/features/branch/Local.feature
index 3b7ab98..509c622 100644
--- a/gremlin-test/features/branch/Local.feature
+++ b/gremlin-test/features/branch/Local.feature
@@ -1,6 +1,6 @@
 # Licensed to the Apache Software Foundation (ASF) under one
-# or more contriAndor license agreements.  See the NOTICE file
-# distriAnded with this work for additional information
+# 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
@@ -9,7 +9,7 @@
 # http://www.apache.org/licenses/LICENSE-2.0
 #
 # Unless required by applicable law or agreed to in writing,
-# software distriAnded under the License is distriAnded on an
+# 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
@@ -67,10 +67,10 @@
 
   Scenario: g_VX1X_localXoutEXknowsX_limitX1XX_inV_name
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).local(__.outE("knows").limit(1)).inV().values("name")
+      g.V(vid1).local(__.outE("knows").limit(1)).inV().values("name")
       """
     When iterated to list
     Then the result should be of
@@ -97,10 +97,10 @@
 
   Scenario: g_VX4X_localXbothEX1_createdX_limitX1XX
     Given the modern graph
-    And using the parameter v4Id defined as "v[josh].id"
+    And using the parameter vid4 defined as "v[josh].id"
     And the traversal of
       """
-      g.V(v4Id).local(__.bothE("created").limit(1))
+      g.V(vid4).local(__.bothE("created").limit(1))
       """
     When iterated to list
     Then the result should be of
@@ -111,10 +111,10 @@
 
   Scenario: g_VX4X_localXbothEXknows_createdX_limitX1XX
     Given the modern graph
-    And using the parameter v4Id defined as "v[josh].id"
+    And using the parameter vid4 defined as "v[josh].id"
     And the traversal of
       """
-      g.V(v4Id).local(__.bothE("knows", "created").limit(1))
+      g.V(vid4).local(__.bothE("knows", "created").limit(1))
       """
     When iterated to list
     Then the result should be of
@@ -126,10 +126,10 @@
 
   Scenario: g_VX4X_localXbothE_limitX1XX_otherV_name
     Given the modern graph
-    And using the parameter v4Id defined as "v[josh].id"
+    And using the parameter vid4 defined as "v[josh].id"
     And the traversal of
       """
-      g.V(v4Id).local(__.bothE().limit(1)).otherV().values("name")
+      g.V(vid4).local(__.bothE().limit(1)).otherV().values("name")
       """
     When iterated to list
     Then the result should be of
@@ -141,10 +141,10 @@
 
   Scenario: g_VX4X_localXbothE_limitX2XX_otherV_name
     Given the modern graph
-    And using the parameter v4Id defined as "v[josh].id"
+    And using the parameter vid4 defined as "v[josh].id"
     And the traversal of
       """
-      g.V(v4Id).local(__.bothE().limit(2)).otherV().values("name")
+      g.V(vid4).local(__.bothE().limit(2)).otherV().values("name")
       """
     When iterated to list
     Then the result should be of
diff --git a/gremlin-test/features/branch/Optional.feature b/gremlin-test/features/branch/Optional.feature
index b69fe13..67fc137 100644
--- a/gremlin-test/features/branch/Optional.feature
+++ b/gremlin-test/features/branch/Optional.feature
@@ -19,10 +19,10 @@
 
   Scenario: g_VX2X_optionalXoutXknowsXX
     Given the modern graph
-    And using the parameter v2Id defined as "v[vadas].id"
+    And using the parameter vid2 defined as "v[vadas].id"
     And the traversal of
       """
-      g.V(v2Id).optional(__.out("knows"))
+      g.V(vid2).optional(__.out("knows"))
       """
     When iterated to list
     Then the result should be unordered
@@ -31,10 +31,10 @@
 
   Scenario: g_VX2X_optionalXinXknowsXX
     Given the modern graph
-    And using the parameter v2Id defined as "v[vadas].id"
+    And using the parameter vid2 defined as "v[vadas].id"
     And the traversal of
       """
-      g.V(v2Id).optional(__.in("knows"))
+      g.V(vid2).optional(__.in("knows"))
       """
     When iterated to list
     Then the result should be unordered
@@ -97,10 +97,10 @@
         addE("created").from("josh").to("lop").property(T.id, 11).property("weight", 0.4).
         addE("created").from("peter").to("lop").property(T.id, 12).property("weight", 0.2)
       """
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).optional(__.addV("dog")).label()
+      g.V(vid1).optional(__.addV("dog")).label()
       """
     When iterated to list
     Then the result should be unordered
diff --git a/gremlin-test/features/branch/Repeat.feature b/gremlin-test/features/branch/Repeat.feature
index 30615a5..223b0ef 100644
--- a/gremlin-test/features/branch/Repeat.feature
+++ b/gremlin-test/features/branch/Repeat.feature
@@ -76,10 +76,10 @@
 
   Scenario: g_VX1X_timesX2X_repeatXoutX_name
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).times(2).repeat(__.out()).values("name")
+      g.V(vid1).times(2).repeat(__.out()).values("name")
       """
     When iterated to list
     Then the result should be unordered
@@ -137,10 +137,10 @@
 
   Scenario: g_VX1X_emitXhasXlabel_personXX_repeatXoutX_name
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).emit(__.has(T.label, "person")).repeat(__.out()).values("name")
+      g.V(vid1).emit(__.has(T.label, "person")).repeat(__.out()).values("name")
       """
     When iterated to list
     Then the result should be unordered
@@ -162,10 +162,10 @@
 
   Scenario: g_VX1X_repeatXgroupCountXmX_byXloopsX_outX_timesX3X_capXmX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).repeat(__.groupCount("m").by(__.loops()).out()).times(3).cap("m")
+      g.V(vid1).repeat(__.groupCount("m").by(__.loops()).out()).times(3).cap("m")
       """
     When iterated to list
     Then the result should be unordered
@@ -185,10 +185,10 @@
 
   Scenario: g_VX1X_repeatXoutX_untilXoutE_count_isX0XX_name
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).repeat(__.out()).until(__.outE().count().is(0)).values("name")
+      g.V(vid1).repeat(__.out()).until(__.outE().count().is(0)).values("name")
       """
     When iterated to list
     Then the result should be unordered
@@ -200,11 +200,10 @@
 
   Scenario: g_V_repeatXbothX_untilXname_eq_marko_or_loops_gt_1X_groupCount_byXnameX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
-    And using the parameter l defined as "c[t -> t.get().value('name').equals('lop') || t.loops() > 1]"
+    And using the parameter pred1 defined as "c[t -> t.get().value('name').equals('lop') || t.loops() > 1]"
     And the traversal of
       """
-      g.V().repeat(__.both()).until(l).groupCount().by("name")
+      g.V().repeat(__.both()).until(pred1).groupCount().by("name")
       """
     When iterated to list
     Then the result should be unordered
@@ -304,10 +303,10 @@
 
 Scenario: g_VX3X_repeatXbothX_createdXX_untilXloops_is_40XXemit_repeatXin_knowsXX_emit_loopsXisX1Xdedup_values
     Given the modern graph
-    And using the parameter v3Id defined as "v[lop].id"
+    And using the parameter vid3 defined as "v[lop].id"
     And the traversal of
       """
-      g.V(v3Id).repeat(__.both("created")).until(__.loops().is(40)).emit(__.repeat(__.in("knows")).emit(__.loops().is(1))).dedup().values("name")
+      g.V(vid3).repeat(__.both("created")).until(__.loops().is(40)).emit(__.repeat(__.in("knows")).emit(__.loops().is(1))).dedup().values("name")
       """
     When iterated to list
       Then the result should be unordered
@@ -318,10 +317,10 @@
 
 Scenario: g_VX1X_repeatXrepeatXunionXout_uses_out_traversesXX_whereXloops_isX0X_timesX1X_timeX2X_name
     Given the crew graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).repeat(__.repeat(__.union(__.out("uses"), __.out("traverses")).where(__.loops().is(0))).times(1)).times(2).values("name")
+      g.V(vid1).repeat(__.repeat(__.union(__.out("uses"), __.out("traverses")).where(__.loops().is(0))).times(1)).times(2).values("name")
       """
     When iterated to list
       Then the result should be unordered
@@ -342,10 +341,10 @@
 
 Scenario: g_VX6X_repeatXa_bothXcreatedX_simplePathX_emitXrepeatXb_bothXknowsXX_untilXloopsXbX_asXb_whereXloopsXaX_asXbX_hasXname_vadasXX_dedup_name
   Given the modern graph
-  And using the parameter v6Id defined as "v[peter].id"
+  And using the parameter vid6 defined as "v[peter].id"
   And the traversal of
     """
-    g.V(v6Id).repeat("a", __.both("created").simplePath()).emit(__.repeat("b", __.both("knows")).until(__.loops("b").as("b").where(__.loops("a").as("b"))).has("name", "vadas")).dedup().values("name")
+    g.V(vid6).repeat("a", __.both("created").simplePath()).emit(__.repeat("b", __.both("knows")).until(__.loops("b").as("b").where(__.loops("a").as("b"))).has("name", "vadas")).dedup().values("name")
     """
   When iterated to list
   Then the result should be unordered
diff --git a/gremlin-test/features/branch/Union.feature b/gremlin-test/features/branch/Union.feature
index 8f5297e..24d7e4d 100644
--- a/gremlin-test/features/branch/Union.feature
+++ b/gremlin-test/features/branch/Union.feature
@@ -41,10 +41,10 @@
 
   Scenario: g_VX1X_unionXrepeatXoutX_timesX2X__outX_name
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).union(__.repeat(__.out()).times(2), __.out()).values("name")
+      g.V(vid1).union(__.repeat(__.out()).times(2), __.out()).values("name")
       """
     When iterated to list
     Then the result should be unordered
@@ -108,11 +108,11 @@
 
   Scenario: g_VX1_2X_unionXoutE_count__inE_count__outE_weight_sumX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
-    And using the parameter v2Id defined as "v[vadas].id"
+    And using the parameter vid1 defined as "v[marko].id"
+    And using the parameter vid2 defined as "v[vadas].id"
     And the traversal of
       """
-      g.V(v1Id, v2Id).union(__.outE().count(), __.inE().count(), __.outE().values("weight").sum())
+      g.V(vid1, vid2).union(__.outE().count(), __.inE().count(), __.outE().values("weight").sum())
       """
     When iterated to list
     Then the result should be unordered
@@ -123,11 +123,11 @@
 
   Scenario: g_VX1_2X_localXunionXoutE_count__inE_count__outE_weight_sumXX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
-    And using the parameter v2Id defined as "v[vadas].id"
+    And using the parameter vid1 defined as "v[marko].id"
+    And using the parameter vid2 defined as "v[vadas].id"
     And the traversal of
       """
-      g.V(v1Id, v2Id).local(__.union(__.outE().count(), __.inE().count(), __.outE().values("weight").sum()))
+      g.V(vid1, vid2).local(__.union(__.outE().count(), __.inE().count(), __.outE().values("weight").sum()))
       """
     When iterated to list
     Then the result should be unordered
@@ -140,11 +140,11 @@
 
   Scenario: g_VX1_2X_localXunionXcountXX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
-    And using the parameter v2Id defined as "v[vadas].id"
+    And using the parameter vid1 defined as "v[marko].id"
+    And using the parameter vid2 defined as "v[vadas].id"
     And the traversal of
       """
-      g.V(v1Id, v2Id).local(__.union(__.count()))
+      g.V(vid1, vid2).local(__.union(__.count()))
       """
     When iterated to list
     Then the result should be unordered
diff --git a/gremlin-test/features/filter/CyclicPath.feature b/gremlin-test/features/filter/CyclicPath.feature
index bfbb3a9..b49bf3b 100644
--- a/gremlin-test/features/filter/CyclicPath.feature
+++ b/gremlin-test/features/filter/CyclicPath.feature
@@ -19,10 +19,10 @@
 
   Scenario: g_VX1X_outXcreatedX_inXcreatedX_cyclicPath
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).out("created").in("created").cyclicPath()
+      g.V(vid1).out("created").in("created").cyclicPath()
       """
     When iterated to list
     Then the result should be unordered
@@ -31,10 +31,10 @@
 
   Scenario: g_VX1X_outXcreatedX_inXcreatedX_cyclicPath_path
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).out("created").in("created").cyclicPath().path()
+      g.V(vid1).out("created").in("created").cyclicPath().path()
       """
     When iterated to list
     Then the result should be unordered
@@ -43,10 +43,10 @@
 
   Scenario: g_VX1X_asXaX_outXcreatedX_asXbX_inXcreatedX_asXcX_cyclicPath_fromXaX_toXbX_path
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).as("a").out("created").as("b").in("created").as("c").cyclicPath().from("a").to("b").path()
+      g.V(vid1).as("a").out("created").as("b").in("created").as("c").cyclicPath().from("a").to("b").path()
       """
     When iterated to list
     Then the result should be empty
diff --git a/gremlin-test/features/filter/Dedup.feature b/gremlin-test/features/filter/Dedup.feature
index b7c0943..c157ac7 100644
--- a/gremlin-test/features/filter/Dedup.feature
+++ b/gremlin-test/features/filter/Dedup.feature
@@ -75,10 +75,10 @@
 
   Scenario: g_V_both_name_order_byXa_bX_dedup_value
     Given the modern graph
-    And using the parameter l defined as "c[a,b -> a.value().compareTo(b.value())]"
+    And using the parameter c1 defined as "c[a,b -> a.value().compareTo(b.value())]"
     And the traversal of
       """
-      g.V().both().properties("name").order().by(l).dedup().value()
+      g.V().both().properties("name").order().by(c1).dedup().value()
       """
     When iterated to list
     Then the result should be unordered
@@ -252,3 +252,35 @@
       | result |
       | lop |
 
+  Scenario: g_V_bothE_properties_dedup_count
+    Given the modern graph
+    And the traversal of
+      """
+      g.V().bothE().properties().dedup().count()
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | d[4].l |
+
+  Scenario: g_V_both_properties_dedup_count
+    Given the modern graph
+    And the traversal of
+      """
+      g.V().both().properties().dedup().count()
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | d[12].l |
+
+  Scenario: g_V_both_properties_properties_dedup_count
+    Given the crew graph
+    And the traversal of
+      """
+      g.V().both().properties().properties().dedup().count()
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | d[21].l |
\ No newline at end of file
diff --git a/gremlin-test/features/filter/Filter.feature b/gremlin-test/features/filter/Filter.feature
index b552578..c85bb22 100644
--- a/gremlin-test/features/filter/Filter.feature
+++ b/gremlin-test/features/filter/Filter.feature
@@ -19,20 +19,20 @@
 
   Scenario: g_V_filterXfalseX
     Given the modern graph
-    And using the parameter l1 defined as "c[false]"
+    And using the parameter pred1 defined as "c[false]"
     And the traversal of
       """
-      g.V().filter(l1)
+      g.V().filter(pred1)
       """
     When iterated to list
     Then the result should be empty
 
   Scenario: g_V_filterXtrueX
     Given the modern graph
-    And using the parameter l1 defined as "c[true]"
+    And using the parameter pred1 defined as "c[true]"
     And the traversal of
       """
-      g.V().filter(l1)
+      g.V().filter(pred1)
       """
     When iterated to list
     Then the result should be unordered
@@ -46,10 +46,10 @@
 
   Scenario: g_V_filterXlang_eq_javaX
     Given the modern graph
-    And using the parameter l1 defined as "c[it.get().property('lang').orElse('none').equals('java')]"
+    And using the parameter pred1 defined as "c[it.get().property('lang').orElse('none').equals('java')]"
     And the traversal of
       """
-      g.V().filter(l1)
+      g.V().filter(pred1)
       """
     When iterated to list
     Then the result should be unordered
@@ -59,22 +59,22 @@
 
   Scenario: g_VX1X_filterXage_gt_30X
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
-    And using the parameter l1 defined as "c[it.get().property('age').orElse(0) > 30]"
+    And using the parameter vid1 defined as "v[marko].id"
+    And using the parameter pred1 defined as "c[it.get().property('age').orElse(0) > 30]"
     And the traversal of
       """
-      g.V(v1Id).filter(l1)
+      g.V(vid1).filter(pred1)
       """
     When iterated to list
     Then the result should be empty
 
   Scenario: g_VX2X_filterXage_gt_30X
     Given the modern graph
-    And using the parameter v2Id defined as "v[josh].id"
-    And using the parameter l1 defined as "c[it.get().property('age').orElse(0) > 30]"
+    And using the parameter vid2 defined as "v[josh].id"
+    And using the parameter pred1 defined as "c[it.get().property('age').orElse(0) > 30]"
     And the traversal of
       """
-      g.V(v2Id).filter(l1)
+      g.V(vid2).filter(pred1)
       """
     When iterated to list
     Then the result should be unordered
@@ -83,11 +83,11 @@
 
   Scenario: g_VX1X_out_filterXage_gt_30X
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
-    And using the parameter l1 defined as "c[it.get().property('age').orElse(0) > 30]"
+    And using the parameter vid1 defined as "v[marko].id"
+    And using the parameter pred1 defined as "c[it.get().property('age').orElse(0) > 30]"
     And the traversal of
       """
-      g.V(v1Id).out().filter(l1)
+      g.V(vid1).out().filter(pred1)
       """
     When iterated to list
     Then the result should be unordered
@@ -96,10 +96,10 @@
 
   Scenario: g_V_filterXname_startsWith_m_OR_name_startsWith_pX
     Given the modern graph
-    And using the parameter l1 defined as "c[{name = it.get().value('name'); name.startsWith('m') || name.startsWith('p')}]"
+    And using the parameter pred1 defined as "c[{name = it.get().value('name'); name.startsWith('m') || name.startsWith('p')}]"
     And the traversal of
       """
-      g.V().filter(l1)
+      g.V().filter(pred1)
       """
     When iterated to list
     Then the result should be unordered
@@ -109,20 +109,20 @@
 
   Scenario: g_E_filterXfalseX
     Given the modern graph
-    And using the parameter l1 defined as "c[false]"
+    And using the parameter pred1 defined as "c[false]"
     And the traversal of
       """
-      g.E().filter(l1)
+      g.E().filter(pred1)
       """
     When iterated to list
     Then the result should be empty
 
   Scenario: g_E_filterXtrueX
     Given the modern graph
-    And using the parameter l1 defined as "c[true]"
+    And using the parameter pred1 defined as "c[true]"
     And the traversal of
       """
-      g.E().filter(l1)
+      g.E().filter(pred1)
       """
     When iterated to list
     Then the result should be unordered
diff --git a/gremlin-test/features/filter/Has.feature b/gremlin-test/features/filter/Has.feature
index 2f08a6b..84ae860 100644
--- a/gremlin-test/features/filter/Has.feature
+++ b/gremlin-test/features/filter/Has.feature
@@ -31,10 +31,10 @@
 
   Scenario: g_VX1X_hasXnameX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).has("name")
+      g.V(vid1).has("name")
       """
     When iterated to list
     Then the result should be unordered
@@ -43,20 +43,20 @@
 
   Scenario: g_VX1X_hasXcircumferenceX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).has("circumference")
+      g.V(vid1).has("circumference")
       """
     When iterated to list
     Then the result should be empty
 
   Scenario: g_VX1X_hasXname_markoX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).has("name", "marko")
+      g.V(vid1).has("name", "marko")
       """
     When iterated to list
     Then the result should be unordered
@@ -65,10 +65,10 @@
 
   Scenario: g_VX2X_hasXname_markoX
     Given the modern graph
-    And using the parameter v1Id defined as "v[vadas].id"
+    And using the parameter vid1 defined as "v[vadas].id"
     And the traversal of
       """
-      g.V(v1Id).has("name", "marko")
+      g.V(vid1).has("name", "marko")
       """
     When iterated to list
     Then the result should be empty
@@ -131,20 +131,20 @@
 
   Scenario: g_VX1X_hasXage_gt_30X
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).has("age", P.gt(30))
+      g.V(vid1).has("age", P.gt(30))
       """
     When iterated to list
     Then the result should be empty
 
   Scenario: g_VX4X_hasXage_gt_30X
     Given the modern graph
-    And using the parameter v4Id defined as "v[josh].id"
+    And using the parameter vid4 defined as "v[josh].id"
     And the traversal of
       """
-      g.V(v4Id).has("age", P.gt(30))
+      g.V(vid4).has("age", P.gt(30))
       """
     When iterated to list
     Then the result should be unordered
@@ -164,10 +164,9 @@
   Scenario: g_VXv4X_hasXage_gt_30X
     Given the modern graph
     And using the parameter v4 defined as "v[josh]"
-    And using the parameter d30 defined as "d[30].i"
     And the traversal of
       """
-      g.V(v4).has("age", P.gt(d30))
+      g.V(v4).has("age", P.gt(30))
       """
     When iterated to list
     Then the result should be unordered
@@ -176,24 +175,20 @@
 
   Scenario: g_VX1X_out_hasXid_lt_3X
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
-    And using the parameter ltXv3IdX of P.lt("v[lop].id")
+    And using the parameter vid1 defined as "v[marko].id"
+    And using the parameter xx1 of P.lt("v[lop].id")
     And the traversal of
       """
-      g.V(v1Id).out().has(T.id, ltXv3IdX)
+      g.V(vid1).out().has(T.id, xx1)
       """
-    When iterated to list
-    Then the result should be unordered
-      | result |
-      | v[vadas] |
 
   Scenario: g_VX1AsStringX_out_hasXid_2AsStringX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].sid"
-    And using the parameter v2Id defined as "v[vadas].sid"
+    And using the parameter vid1 defined as "v[marko].sid"
+    And using the parameter vid2 defined as "v[vadas].sid"
     And the traversal of
       """
-      g.V(v1Id).out().hasId(v2Id)
+      g.V(vid1).out().hasId(vid2)
       """
     When iterated to list
     Then the result should be unordered
@@ -214,11 +209,11 @@
 
   Scenario: g_VX1X_out_hasIdX2X
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
-    And using the parameter v2Id defined as "v[vadas].id"
+    And using the parameter vid1 defined as "v[marko].id"
+    And using the parameter vid2 defined as "v[vadas].id"
     And the traversal of
       """
-      g.V(v1Id).out().hasId(v2Id)
+      g.V(vid1).out().hasId(vid2)
       """
     When iterated to list
     Then the result should be unordered
@@ -227,12 +222,12 @@
 
   Scenario: g_VX1X_out_hasXid_2_3X
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
-    And using the parameter v2Id defined as "v[vadas].id"
-    And using the parameter v3Id defined as "v[lop].id"
+    And using the parameter vid1 defined as "v[marko].id"
+    And using the parameter vid2 defined as "v[vadas].id"
+    And using the parameter vid3 defined as "v[lop].id"
     And the traversal of
       """
-      g.V(v1Id).out().hasId(v2Id, v3Id)
+      g.V(vid1).out().hasId(vid2, vid3)
       """
     When iterated to list
     Then the result should be unordered
@@ -242,12 +237,12 @@
 
   Scenario: g_VX1X_out_hasXid_2AsString_3AsStringX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].sid"
-    And using the parameter v2Id defined as "v[vadas].sid"
-    And using the parameter v3Id defined as "v[lop].sid"
+    And using the parameter vid1 defined as "v[marko].sid"
+    And using the parameter vid2 defined as "v[vadas].sid"
+    And using the parameter vid3 defined as "v[lop].sid"
     And the traversal of
       """
-      g.V(v1Id).out().hasId(v2Id, v3Id)
+      g.V(vid1).out().hasId(vid2, vid3)
       """
     When iterated to list
     Then the result should be unordered
@@ -266,10 +261,10 @@
 
   Scenario: g_EX7X_hasXlabelXknowsX
     Given the modern graph
-    And using the parameter e7Id defined as "e[marko-knows->vadas].id"
+    And using the parameter eid7 defined as "e[marko-knows->vadas].id"
     And the traversal of
       """
-      g.E(e7Id).hasLabel("knows")
+      g.E(eid7).hasLabel("knows")
       """
     When iterated to list
     Then the result should be unordered
@@ -336,12 +331,10 @@
 
   Scenario: g_VX1X_outE_hasXweight_inside_0_06X_inV
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
-    And using the parameter lower defined as "d[0.0].d"
-    And using the parameter upper defined as "d[0.6].d"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
     """
-    g.V(v1Id).outE().has("weight", P.inside(lower, upper)).inV()
+    g.V(vid1).outE().has("weight", P.inside(0.0, 0.6)).inV()
     """
     When iterated to list
     Then the result should be unordered
@@ -351,11 +344,11 @@
 
   Scenario: g_EX11X_outV_outE_hasXid_10X
     Given the modern graph
-    And using the parameter e11Id defined as "e[josh-created->lop].id"
-    And using the parameter e10Id defined as "e[josh-created->ripple].id"
+    And using the parameter eid11 defined as "e[josh-created->lop].id"
+    And using the parameter eid10 defined as "e[josh-created->ripple].id"
     And the traversal of
     """
-    g.E(e11Id).outV().outE().has(T.id, e10Id)
+    g.E(eid11).outV().outE().has(T.id, eid10)
     """
     When iterated to list
     Then the result should be unordered
@@ -364,11 +357,11 @@
 
   Scenario: g_EX11X_outV_outE_hasXid_10AsStringX
     Given the modern graph
-    And using the parameter e11Id defined as "e[josh-created->lop].sid"
-    And using the parameter e10Id defined as "e[josh-created->ripple].sid"
+    And using the parameter eid11 defined as "e[josh-created->lop].sid"
+    And using the parameter eid10 defined as "e[josh-created->ripple].sid"
     And the traversal of
     """
-    g.E(e11Id).outV().outE().has(T.id, e10Id)
+    g.E(eid11).outV().outE().has(T.id, eid10)
     """
     When iterated to list
     Then the result should be unordered
@@ -391,14 +384,9 @@
 
   Scenario: g_V_hasLabelXpersonX_hasXage_notXlteX10X_andXnotXbetweenX11_20XXXX_andXltX29X_orXeqX35XXXX_name
     Given the modern graph
-    And using the parameter d10 defined as "d[10].i"
-    And using the parameter d11 defined as "d[11].i"
-    And using the parameter d20 defined as "d[20].i"
-    And using the parameter d29 defined as "d[29].i"
-    And using the parameter d35 defined as "d[35].i"
     And the traversal of
     """
-    g.V().hasLabel("person").has("age", P.not(P.lte(d10).and(P.not(P.between(d11, d20)))).and(P.lt(d29).or(P.eq(d35)))).values("name")
+    g.V().hasLabel("person").has("age", P.not(P.lte(10).and(P.not(P.between(11, 20)))).and(P.lt(29).or(P.eq(35)))).values("name")
     """
     When iterated to list
     Then the result should be unordered
@@ -408,10 +396,10 @@
 
   Scenario: g_V_in_hasIdXneqX1XX
     Given the modern graph
-    And using the parameter neqXv1IdX of P.neq("v[marko].id")
+    And using the parameter xx1 of P.neq("v[marko].id")
     And the traversal of
     """
-    g.V().in().hasId(neqXv1IdX)
+    g.V().in().hasId(xx1)
     """
     When iterated to list
     Then the result should be unordered
@@ -480,10 +468,9 @@
 
   Scenario: g_V_both_dedup_properties_hasKeyXageX_hasValueXgtX30XX_value
     Given the modern graph
-    And using the parameter d30 defined as "d[30].i"
     And the traversal of
     """
-    g.V().both().properties().dedup().hasKey("age").hasValue(P.gt(d30)).value()
+    g.V().both().properties().dedup().hasKey("age").hasValue(P.gt(30)).value()
     """
     When iterated to list
     Then the result should be unordered
@@ -507,7 +494,6 @@
 
   Scenario: g_V_bothE_properties_dedup_hasKeyXweightX_hasValueXltX0d3XX_value
     Given the modern graph
-    And using the parameter d0d3 defined as "d[0.3].d"
     And the traversal of
     """
     g.V().bothE().properties().dedup().hasKey("weight").hasValue(P.lt(0.3)).value()
@@ -531,11 +517,11 @@
 
   Scenario: g_V_hasIdX1X_hasIdX2X
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
-    And using the parameter v2Id defined as "v[vadas].id"
+    And using the parameter vid1 defined as "v[marko].id"
+    And using the parameter vid2 defined as "v[vadas].id"
     And the traversal of
     """
-    g.V().hasId(v1Id).hasId(v2Id)
+    g.V().hasId(vid1).hasId(vid2)
     """
     When iterated to list
     Then the result should be empty
@@ -551,10 +537,10 @@
 
   Scenario: g_V_hasIdXemptyX_count
     Given the modern graph
-    And using the parameter l defined as "l[]"
+    And using the parameter xx1 defined as "l[]"
     And the traversal of
     """
-    g.V().hasId(l).count()
+    g.V().hasId(xx1).count()
     """
     When iterated to list
     Then the result should be unordered
@@ -563,10 +549,10 @@
 
   Scenario: g_V_hasIdXwithinXemptyXX_count
     Given the modern graph
-    And using the parameter withinXlX of P.within("l[]")
+    And using the parameter xx1 of P.within("l[]")
     And the traversal of
     """
-    g.V().hasId(withinXlX).count()
+    g.V().hasId(xx1).count()
     """
     When iterated to list
     Then the result should be unordered
@@ -575,10 +561,10 @@
 
   Scenario: g_V_hasIdXwithoutXemptyXX_count
     Given the modern graph
-    And using the parameter withoutXlX of P.without("l[]")
+    And using the parameter xx1 of P.without("l[]")
     And the traversal of
     """
-    g.V().hasId(withoutXlX).count()
+    g.V().hasId(xx1).count()
     """
     When iterated to list
     Then the result should be unordered
@@ -587,10 +573,10 @@
 
   Scenario: g_V_notXhasIdXwithinXemptyXXX_count
     Given the modern graph
-    And using the parameter withinXlX of P.within("l[]")
+    And using the parameter xx1 of P.within("l[]")
     And the traversal of
     """
-    g.V().not(__.hasId(withinXlX)).count()
+    g.V().not(__.hasId(xx1)).count()
     """
     When iterated to list
     Then the result should be unordered
@@ -704,4 +690,28 @@
       g.V().has("p", P.neq("v"))
       """
     When iterated to list
-    Then the result should be empty
\ No newline at end of file
+    Then the result should be empty
+
+  Scenario: g_V_hasXage_gtX18X_andXltX30XXorXgtx35XXX
+    Given the modern graph
+    And the traversal of
+      """
+      g.V().has("age", P.gt(18).and(P.lt(30)).or(P.gt(35)))
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | v[marko] |
+      | v[vadas] |
+
+  Scenario: g_V_hasXage_gtX18X_andXltX30XXorXltx35XXX
+    Given the modern graph
+    And the traversal of
+      """
+      g.V().has("age", P.gt(18).and(P.lt(30)).and(P.lt(35)))
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | v[marko] |
+      | v[vadas] |
\ No newline at end of file
diff --git a/gremlin-test/features/filter/Is.feature b/gremlin-test/features/filter/Is.feature
index 4eec274..9a68d18 100644
--- a/gremlin-test/features/filter/Is.feature
+++ b/gremlin-test/features/filter/Is.feature
@@ -67,7 +67,7 @@
     Given the modern graph
     And the traversal of
       """
-      g.V().where(__.in("created").count().is(P.gte(2l))).values("name")
+      g.V().where(__.in("created").count().is(P.gte(2))).values("name")
       """
     When iterated to list
     Then the result should be unordered
diff --git a/gremlin-test/features/filter/Or.feature b/gremlin-test/features/filter/Or.feature
index 7f4782d..b294532 100644
--- a/gremlin-test/features/filter/Or.feature
+++ b/gremlin-test/features/filter/Or.feature
@@ -21,7 +21,7 @@
     Given the modern graph
     And the traversal of
       """
-      g.V().or(__.has("age", P.gt(27)), __.outE().count().is(P.gte(2l))).values("name")
+      g.V().or(__.has("age", P.gt(27)), __.outE().count().is(P.gte(2))).values("name")
       """
     When iterated to list
     Then the result should be unordered
diff --git a/gremlin-test/features/filter/Range.feature b/gremlin-test/features/filter/Range.feature
index fd3c63f..62f62a5 100644
--- a/gremlin-test/features/filter/Range.feature
+++ b/gremlin-test/features/filter/Range.feature
@@ -19,10 +19,10 @@
 
   Scenario: g_VX1X_out_limitX2X
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).out().limit(2)
+      g.V(vid1).out().limit(2)
       """
     When iterated to list
     Then the result should be of
@@ -49,10 +49,10 @@
 
   Scenario: g_VX1X_outXknowsX_outEXcreatedX_rangeX0_1X_inV
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).out("knows").outE("created").range(0, 1).inV()
+      g.V(vid1).out("knows").outE("created").range(0, 1).inV()
       """
     When iterated to list
     Then the result should be of
@@ -63,10 +63,10 @@
 
   Scenario: g_VX1X_outXknowsX_outXcreatedX_rangeX0_1X
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).out("knows").out("created").range(0, 1)
+      g.V(vid1).out("knows").out("created").range(0, 1)
       """
     When iterated to list
     Then the result should be of
@@ -77,10 +77,10 @@
 
   Scenario: g_VX1X_outXcreatedX_inXcreatedX_rangeX1_3X
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).out("created").in("created").range(1, 3)
+      g.V(vid1).out("created").in("created").range(1, 3)
       """
     When iterated to list
     Then the result should be of
@@ -92,10 +92,10 @@
 
   Scenario: g_VX1X_outXcreatedX_inEXcreatedX_rangeX1_3X_outV
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).out("created").inE("created").range(1, 3).outV()
+      g.V(vid1).out("created").inE("created").range(1, 3).outV()
       """
     When iterated to list
     Then the result should be of
diff --git a/gremlin-test/features/filter/Sample.feature b/gremlin-test/features/filter/Sample.feature
index ab3a9ae..eb7d3a3 100644
--- a/gremlin-test/features/filter/Sample.feature
+++ b/gremlin-test/features/filter/Sample.feature
@@ -28,7 +28,6 @@
 
   Scenario: g_E_sampleX2X_byXweightX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
     And the traversal of
       """
       g.E().sample(2).by("weight")
diff --git a/gremlin-test/features/filter/SimplePath.feature b/gremlin-test/features/filter/SimplePath.feature
index ed66e8b..97a1b9b 100644
--- a/gremlin-test/features/filter/SimplePath.feature
+++ b/gremlin-test/features/filter/SimplePath.feature
@@ -19,10 +19,10 @@
 
   Scenario: g_VX1X_outXcreatedX_inXcreatedX_simplePath
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).out("created").in("created").simplePath()
+      g.V(vid1).out("created").in("created").simplePath()
       """
     When iterated to list
     Then the result should be unordered
@@ -60,7 +60,6 @@
 
   Scenario: g_V_asXaX_out_asXbX_out_asXcX_simplePath_byXlabelX_fromXbX_toXcX_path_byXnameX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
     And the traversal of
       """
       g.V().as("a").out().as("b").out().as("c").simplePath().by(T.label).from("b").to("c").path().by("name")
diff --git a/gremlin-test/features/filter/Where.feature b/gremlin-test/features/filter/Where.feature
index 912edf2..374c63c 100644
--- a/gremlin-test/features/filter/Where.feature
+++ b/gremlin-test/features/filter/Where.feature
@@ -91,11 +91,11 @@
 
   Scenario: g_withSideEffectXa_josh_peterX_VX1X_outXcreatedX_inXcreatedX_name_whereXwithinXaXX
     Given the modern graph
-    And using the parameter l defined as "l[josh,peter]"
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter xx1 defined as "l[josh,peter]"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.withSideEffect("a", l).V(v1Id).out("created").in("created").values("name").where(P.within("a"))
+      g.withSideEffect("a", xx1).V(vid1).out("created").in("created").values("name").where(P.within("a"))
       """
     When iterated to list
     Then the result should be unordered
@@ -105,10 +105,10 @@
 
   Scenario: g_VX1X_asXaX_outXcreatedX_inXcreatedX_asXbX_whereXa_neqXbXX_name
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).as("a").out("created").in("created").as("b").where("a", P.neq("b")).values("name")
+      g.V(vid1).as("a").out("created").in("created").as("b").where("a", P.neq("b")).values("name")
       """
     When iterated to list
     Then the result should be unordered
@@ -118,10 +118,10 @@
 
   Scenario: g_VX1X_asXaX_outXcreatedX_inXcreatedX_asXbX_whereXasXbX_outXcreatedX_hasXname_rippleXX_valuesXage_nameX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).as("a").out("created").in("created").as("b").where(__.as("b").out("created").has("name", "ripple")).values("age", "name")
+      g.V(vid1).as("a").out("created").in("created").as("b").where(__.as("b").out("created").has("name", "ripple")).values("age", "name")
       """
     When iterated to list
     Then the result should be unordered
@@ -131,10 +131,10 @@
 
   Scenario: g_VX1X_asXaX_outXcreatedX_inXcreatedX_whereXeqXaXX_name
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).as("a").out("created").in("created").where(P.eq("a")).values("name")
+      g.V(vid1).as("a").out("created").in("created").where(P.eq("a")).values("name")
       """
     When iterated to list
     Then the result should be unordered
@@ -143,10 +143,10 @@
 
   Scenario: g_VX1X_asXaX_outXcreatedX_inXcreatedX_whereXneqXaXX_name
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).as("a").out("created").in("created").where(P.neq("a")).values("name")
+      g.V(vid1).as("a").out("created").in("created").where(P.neq("a")).values("name")
       """
     When iterated to list
     Then the result should be unordered
@@ -156,10 +156,10 @@
 
   Scenario: g_VX1X_out_aggregateXxX_out_whereXnotXwithinXaXXX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).out().aggregate("x").out().where(P.not(P.within("x")))
+      g.V(vid1).out().aggregate("x").out().where(P.not(P.within("x")))
       """
     When iterated to list
     Then the result should be unordered
@@ -168,11 +168,11 @@
 
   Scenario: g_withSideEffectXa_g_VX2XX_VX1X_out_whereXneqXaXX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And using the parameter v2 defined as "v[vadas]"
     And the traversal of
       """
-      g.withSideEffect("a", v2).V(v1Id).out().where(P.neq("a"))
+      g.withSideEffect("a", v2).V(vid1).out().where(P.neq("a"))
       """
     When iterated to list
     Then the result should be unordered
@@ -182,10 +182,10 @@
 
   Scenario: g_VX1X_repeatXbothEXcreatedX_whereXwithoutXeXX_aggregateXeX_otherVX_emit_path
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).repeat(__.bothE("created").where(P.without("e")).aggregate("e").otherV()).emit().path()
+      g.V(vid1).repeat(__.bothE("created").where(P.without("e")).aggregate("e").otherV()).emit().path()
       """
     When iterated to list
     Then the result should be unordered
@@ -314,10 +314,10 @@
 
   Scenario: g_VX1X_asXaX_out_hasXageX_whereXgtXaXX_byXageX_name
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).as("a").out().has("age").where(P.gt("a")).by("age").values("name")
+      g.V(vid1).as("a").out().has("age").where(P.gt("a")).by("age").values("name")
       """
     When iterated to list
     Then the result should be unordered
diff --git a/gremlin-test/features/map/AddEdge.feature b/gremlin-test/features/map/AddEdge.feature
index 7f4b0aa..4795cbf 100644
--- a/gremlin-test/features/map/AddEdge.feature
+++ b/gremlin-test/features/map/AddEdge.feature
@@ -34,15 +34,15 @@
         addE("created").from("josh").to("lop").property(T.id, 11).property("weight", 0.4).
         addE("created").from("peter").to("lop").property(T.id, 12).property("weight", 0.2)
       """
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).as("a").out("created").addE("createdBy").to("a")
+      g.V(vid1).as("a").out("created").addE("createdBy").to("a")
       """
     When iterated to list
     Then the result should have a count of 1
     And the graph should return 7 for count of "g.E()"
-    And the graph should return 1 for count of "g.V(v1Id).inE()"
+    And the graph should return 1 for count of "g.V(vid1).inE()"
 
   Scenario: g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX_propertyXweight_2X
     Given the empty graph
@@ -61,16 +61,41 @@
         addE("created").from("josh").to("lop").property(T.id, 11).property("weight", 0.4).
         addE("created").from("peter").to("lop").property(T.id, 12).property("weight", 0.2)
       """
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).as("a").out("created").addE("createdBy").to("a").property("weight", 2.0)
+      g.V(vid1).as("a").out("created").addE("createdBy").to("a").property("weight", 2.0)
       """
     When iterated to list
     Then the result should have a count of 1
     And the graph should return 7 for count of "g.E()"
-    And the graph should return 4 for count of "g.V(v1Id).bothE()"
-    And the graph should return 1 for count of "g.V(v1Id).inE().has(\"weight\", 2.0)"
+    And the graph should return 4 for count of "g.V(vid1).bothE()"
+    And the graph should return 1 for count of "g.V(vid1).inE().has(\"weight\", 2.0)"
+
+  Scenario: g_V_outE_propertyXweight_nullX
+    Given the empty graph
+    And the graph initializer of
+      """
+      g.addV("person").property(T.id, 1).property("name", "marko").property("age", 29).as("marko").
+        addV("person").property(T.id, 2).property("name", "vadas").property("age", 27).as("vadas").
+        addV("software").property(T.id, 3).property("name", "lop").property("lang", "java").as("lop").
+        addV("person").property(T.id, 4).property("name","josh").property("age", 32).as("josh").
+        addV("software").property(T.id, 5).property("name", "ripple").property("lang", "java").as("ripple").
+        addV("person").property(T.id, 6).property("name", "peter").property("age", 35).as('peter').
+        addE("knows").from("marko").to("vadas").property(T.id, 7).property("weight", 0.5).
+        addE("knows").from("marko").to("josh").property(T.id, 8).property("weight", 1.0).
+        addE("created").from("marko").to("lop").property(T.id, 9).property("weight", 0.4).
+        addE("created").from("josh").to("ripple").property(T.id, 10).property("weight", 1.0).
+        addE("created").from("josh").to("lop").property(T.id, 11).property("weight", 0.4).
+        addE("created").from("peter").to("lop").property(T.id, 12).property("weight", 0.2)
+      """
+    And the traversal of
+      """
+      g.V().outE().property("weight", null)
+      """
+    When iterated to list
+    Then the result should have a count of 6
+    And the graph should return 0 for count of "g.E().properties(\"weight\")"
 
   Scenario: g_V_aggregateXxX_asXaX_selectXxX_unfold_addEXexistsWithX_toXaX_propertyXtime_nowX
     Given the empty graph
@@ -89,12 +114,12 @@
         addE("created").from("josh").to("lop").property(T.id, 11).property("weight", 0.4).
         addE("created").from("peter").to("lop").property(T.id, 12).property("weight", 0.2)
       """
-    And using the parameter v1Id defined as "v[marko].id"
-    And using the parameter v2Id defined as "v[vadas].id"
-    And using the parameter v3Id defined as "v[lop].id"
-    And using the parameter v4Id defined as "v[josh].id"
-    And using the parameter v5Id defined as "v[ripple].id"
-    And using the parameter v6Id defined as "v[peter].id"
+    And using the parameter vid1 defined as "v[marko].id"
+    And using the parameter vid2 defined as "v[vadas].id"
+    And using the parameter vid3 defined as "v[lop].id"
+    And using the parameter vid4 defined as "v[josh].id"
+    And using the parameter vid5 defined as "v[ripple].id"
+    And using the parameter vid6 defined as "v[peter].id"
     And the traversal of
       """
       g.V().aggregate("x").as("a").select("x").unfold().addE("existsWith").to("a").property("time", "now")
@@ -102,30 +127,30 @@
     When iterated to list
     Then the result should have a count of 36
     And the graph should return 42 for count of "g.E()"
-    And the graph should return 15 for count of "g.V(v1Id).bothE()"
-    And the graph should return 6 for count of "g.V(v1Id).inE(\"existsWith\")"
-    And the graph should return 6 for count of "g.V(v1Id).outE(\"existsWith\")"
-    And the graph should return 12 for count of "g.V(v1Id).bothE(\"existsWith\").has(\"time\",\"now\")"
-    And the graph should return 13 for count of "g.V(v2Id).bothE()"
-    And the graph should return 6 for count of "g.V(v2Id).inE(\"existsWith\")"
-    And the graph should return 6 for count of "g.V(v2Id).outE(\"existsWith\")"
-    And the graph should return 12 for count of "g.V(v2Id).bothE(\"existsWith\").has(\"time\",\"now\")"
-    And the graph should return 15 for count of "g.V(v3Id).bothE()"
-    And the graph should return 6 for count of "g.V(v3Id).inE(\"existsWith\")"
-    And the graph should return 6 for count of "g.V(v3Id).outE(\"existsWith\")"
-    And the graph should return 12 for count of "g.V(v3Id).bothE(\"existsWith\").has(\"time\",\"now\")"
-    And the graph should return 15 for count of "g.V(v4Id).bothE()"
-    And the graph should return 6 for count of "g.V(v4Id).inE(\"existsWith\")"
-    And the graph should return 6 for count of "g.V(v4Id).outE(\"existsWith\")"
-    And the graph should return 12 for count of "g.V(v4Id).bothE(\"existsWith\").has(\"time\",\"now\")"
-    And the graph should return 13 for count of "g.V(v5Id).bothE()"
-    And the graph should return 6 for count of "g.V(v5Id).inE(\"existsWith\")"
-    And the graph should return 6 for count of "g.V(v5Id).outE(\"existsWith\")"
-    And the graph should return 12 for count of "g.V(v5Id).bothE(\"existsWith\").has(\"time\",\"now\")"
-    And the graph should return 13 for count of "g.V(v6Id).bothE()"
-    And the graph should return 6 for count of "g.V(v6Id).inE(\"existsWith\")"
-    And the graph should return 6 for count of "g.V(v6Id).outE(\"existsWith\")"
-    And the graph should return 12 for count of "g.V(v6Id).bothE(\"existsWith\").has(\"time\",\"now\")"
+    And the graph should return 15 for count of "g.V(vid1).bothE()"
+    And the graph should return 6 for count of "g.V(vid1).inE(\"existsWith\")"
+    And the graph should return 6 for count of "g.V(vid1).outE(\"existsWith\")"
+    And the graph should return 12 for count of "g.V(vid1).bothE(\"existsWith\").has(\"time\",\"now\")"
+    And the graph should return 13 for count of "g.V(vid2).bothE()"
+    And the graph should return 6 for count of "g.V(vid2).inE(\"existsWith\")"
+    And the graph should return 6 for count of "g.V(vid2).outE(\"existsWith\")"
+    And the graph should return 12 for count of "g.V(vid2).bothE(\"existsWith\").has(\"time\",\"now\")"
+    And the graph should return 15 for count of "g.V(vid3).bothE()"
+    And the graph should return 6 for count of "g.V(vid3).inE(\"existsWith\")"
+    And the graph should return 6 for count of "g.V(vid3).outE(\"existsWith\")"
+    And the graph should return 12 for count of "g.V(vid3).bothE(\"existsWith\").has(\"time\",\"now\")"
+    And the graph should return 15 for count of "g.V(vid4).bothE()"
+    And the graph should return 6 for count of "g.V(vid4).inE(\"existsWith\")"
+    And the graph should return 6 for count of "g.V(vid4).outE(\"existsWith\")"
+    And the graph should return 12 for count of "g.V(vid4).bothE(\"existsWith\").has(\"time\",\"now\")"
+    And the graph should return 13 for count of "g.V(vid5).bothE()"
+    And the graph should return 6 for count of "g.V(vid5).inE(\"existsWith\")"
+    And the graph should return 6 for count of "g.V(vid5).outE(\"existsWith\")"
+    And the graph should return 12 for count of "g.V(vid5).bothE(\"existsWith\").has(\"time\",\"now\")"
+    And the graph should return 13 for count of "g.V(vid6).bothE()"
+    And the graph should return 6 for count of "g.V(vid6).inE(\"existsWith\")"
+    And the graph should return 6 for count of "g.V(vid6).outE(\"existsWith\")"
+    And the graph should return 12 for count of "g.V(vid6).bothE(\"existsWith\").has(\"time\",\"now\")"
 
   Scenario: g_V_asXaX_outXcreatedX_inXcreatedX_whereXneqXaXX_asXbX_addEXcodeveloperX_fromXaX_toXbX_propertyXyear_2009X
     Given the empty graph
@@ -144,10 +169,10 @@
         addE("created").from("josh").to("lop").property(T.id, 11).property("weight", 0.4).
         addE("created").from("peter").to("lop").property(T.id, 12).property("weight", 0.2)
       """
-    And using the parameter v1Id defined as "v[marko].id"
-    And using the parameter v2Id defined as "v[vadas].id"
-    And using the parameter v4Id defined as "v[josh].id"
-    And using the parameter v6Id defined as "v[peter].id"
+    And using the parameter vid1 defined as "v[marko].id"
+    And using the parameter vid2 defined as "v[vadas].id"
+    And using the parameter vid4 defined as "v[josh].id"
+    And using the parameter vid6 defined as "v[peter].id"
     And the traversal of
       """
       g.V().as("a").out("created").in("created").where(P.neq("a")).as("b").addE("codeveloper").from("a").to("b").property("year", 2009)
@@ -155,19 +180,19 @@
     When iterated to list
     Then the result should have a count of 6
     And the graph should return 12 for count of "g.E()"
-    And the graph should return 7 for count of "g.V(v1Id).bothE()"
-    And the graph should return 2 for count of "g.V(v1Id).inE(\"codeveloper\")"
-    And the graph should return 2 for count of "g.V(v1Id).outE(\"codeveloper\")"
-    And the graph should return 4 for count of "g.V(v1Id).bothE(\"codeveloper\").has(\"year\",2009)"
-    And the graph should return 1 for count of "g.V(v2Id).bothE()"
-    And the graph should return 7 for count of "g.V(v4Id).bothE()"
-    And the graph should return 2 for count of "g.V(v4Id).inE(\"codeveloper\")"
-    And the graph should return 2 for count of "g.V(v4Id).outE(\"codeveloper\")"
-    And the graph should return 4 for count of "g.V(v4Id).bothE(\"codeveloper\").has(\"year\",2009)"
-    And the graph should return 5 for count of "g.V(v6Id).bothE()"
-    And the graph should return 2 for count of "g.V(v6Id).inE(\"codeveloper\")"
-    And the graph should return 2 for count of "g.V(v6Id).outE(\"codeveloper\")"
-    And the graph should return 4 for count of "g.V(v6Id).bothE(\"codeveloper\").has(\"year\",2009)"
+    And the graph should return 7 for count of "g.V(vid1).bothE()"
+    And the graph should return 2 for count of "g.V(vid1).inE(\"codeveloper\")"
+    And the graph should return 2 for count of "g.V(vid1).outE(\"codeveloper\")"
+    And the graph should return 4 for count of "g.V(vid1).bothE(\"codeveloper\").has(\"year\",2009)"
+    And the graph should return 1 for count of "g.V(vid2).bothE()"
+    And the graph should return 7 for count of "g.V(vid4).bothE()"
+    And the graph should return 2 for count of "g.V(vid4).inE(\"codeveloper\")"
+    And the graph should return 2 for count of "g.V(vid4).outE(\"codeveloper\")"
+    And the graph should return 4 for count of "g.V(vid4).bothE(\"codeveloper\").has(\"year\",2009)"
+    And the graph should return 5 for count of "g.V(vid6).bothE()"
+    And the graph should return 2 for count of "g.V(vid6).inE(\"codeveloper\")"
+    And the graph should return 2 for count of "g.V(vid6).outE(\"codeveloper\")"
+    And the graph should return 4 for count of "g.V(vid6).bothE(\"codeveloper\").has(\"year\",2009)"
 
   Scenario: g_V_asXaX_inXcreatedX_addEXcreatedByX_fromXaX_propertyXyear_2009X_propertyXacl_publicX
     Given the empty graph
@@ -186,12 +211,12 @@
         addE("created").from("josh").to("lop").property(T.id, 11).property("weight", 0.4).
         addE("created").from("peter").to("lop").property(T.id, 12).property("weight", 0.2)
       """
-    And using the parameter v1Id defined as "v[marko].id"
-    And using the parameter v2Id defined as "v[vadas].id"
-    And using the parameter v3Id defined as "v[lop].id"
-    And using the parameter v4Id defined as "v[josh].id"
-    And using the parameter v5Id defined as "v[ripple].id"
-    And using the parameter v6Id defined as "v[peter].id"
+    And using the parameter vid1 defined as "v[marko].id"
+    And using the parameter vid2 defined as "v[vadas].id"
+    And using the parameter vid3 defined as "v[lop].id"
+    And using the parameter vid4 defined as "v[josh].id"
+    And using the parameter vid5 defined as "v[ripple].id"
+    And using the parameter vid6 defined as "v[peter].id"
     And the traversal of
       """
       g.V().as("a").in("created").addE("createdBy").from("a").property("year", 2009).property("acl", "public")
@@ -199,27 +224,27 @@
     When iterated to list
     Then the result should have a count of 4
     And the graph should return 10 for count of "g.E()"
-    And the graph should return 4 for count of "g.V(v1Id).bothE()"
-    And the graph should return 1 for count of "g.V(v1Id).inE(\"createdBy\")"
-    And the graph should return 0 for count of "g.V(v1Id).outE(\"createdBy\")"
-    And the graph should return 1 for count of "g.V(v1Id).bothE(\"createdBy\").has(\"year\",2009).has(\"acl\", \"public\")"
-    And the graph should return 1 for count of "g.V(v2Id).bothE()"
-    And the graph should return 6 for count of "g.V(v3Id).bothE()"
-    And the graph should return 0 for count of "g.V(v3Id).inE(\"createdBy\")"
-    And the graph should return 3 for count of "g.V(v3Id).outE(\"createdBy\")"
-    And the graph should return 3 for count of "g.V(v3Id).bothE(\"createdBy\").has(\"year\",2009).has(\"acl\", \"public\")"
-    And the graph should return 5 for count of "g.V(v4Id).bothE()"
-    And the graph should return 2 for count of "g.V(v4Id).inE(\"createdBy\")"
-    And the graph should return 0 for count of "g.V(v4Id).outE(\"createdBy\")"
-    And the graph should return 2 for count of "g.V(v4Id).bothE(\"createdBy\").has(\"year\",2009).has(\"acl\", \"public\")"
-    And the graph should return 2 for count of "g.V(v5Id).bothE()"
-    And the graph should return 0 for count of "g.V(v5Id).inE(\"createdBy\")"
-    And the graph should return 1 for count of "g.V(v5Id).outE(\"createdBy\")"
-    And the graph should return 1 for count of "g.V(v5Id).bothE(\"createdBy\").has(\"year\",2009).has(\"acl\", \"public\")"
-    And the graph should return 2 for count of "g.V(v6Id).bothE()"
-    And the graph should return 1 for count of "g.V(v6Id).inE(\"createdBy\")"
-    And the graph should return 0 for count of "g.V(v6Id).outE(\"createdBy\")"
-    And the graph should return 1 for count of "g.V(v6Id).bothE(\"createdBy\").has(\"year\",2009).has(\"acl\", \"public\")"
+    And the graph should return 4 for count of "g.V(vid1).bothE()"
+    And the graph should return 1 for count of "g.V(vid1).inE(\"createdBy\")"
+    And the graph should return 0 for count of "g.V(vid1).outE(\"createdBy\")"
+    And the graph should return 1 for count of "g.V(vid1).bothE(\"createdBy\").has(\"year\",2009).has(\"acl\", \"public\")"
+    And the graph should return 1 for count of "g.V(vid2).bothE()"
+    And the graph should return 6 for count of "g.V(vid3).bothE()"
+    And the graph should return 0 for count of "g.V(vid3).inE(\"createdBy\")"
+    And the graph should return 3 for count of "g.V(vid3).outE(\"createdBy\")"
+    And the graph should return 3 for count of "g.V(vid3).bothE(\"createdBy\").has(\"year\",2009).has(\"acl\", \"public\")"
+    And the graph should return 5 for count of "g.V(vid4).bothE()"
+    And the graph should return 2 for count of "g.V(vid4).inE(\"createdBy\")"
+    And the graph should return 0 for count of "g.V(vid4).outE(\"createdBy\")"
+    And the graph should return 2 for count of "g.V(vid4).bothE(\"createdBy\").has(\"year\",2009).has(\"acl\", \"public\")"
+    And the graph should return 2 for count of "g.V(vid5).bothE()"
+    And the graph should return 0 for count of "g.V(vid5).inE(\"createdBy\")"
+    And the graph should return 1 for count of "g.V(vid5).outE(\"createdBy\")"
+    And the graph should return 1 for count of "g.V(vid5).bothE(\"createdBy\").has(\"year\",2009).has(\"acl\", \"public\")"
+    And the graph should return 2 for count of "g.V(vid6).bothE()"
+    And the graph should return 1 for count of "g.V(vid6).inE(\"createdBy\")"
+    And the graph should return 0 for count of "g.V(vid6).outE(\"createdBy\")"
+    And the graph should return 1 for count of "g.V(vid6).bothE(\"createdBy\").has(\"year\",2009).has(\"acl\", \"public\")"
 
   Scenario: g_withSideEffectXb_bX_VXaX_addEXknowsX_toXbX_propertyXweight_0_5X
     Given the empty graph
@@ -350,10 +375,10 @@
       """
     And using the parameter v1 defined as "v[marko]"
     And using the parameter v6 defined as "v[peter]"
-    And using the parameter dotOne defined as "d[0.1].d"
+    And using the parameter xx1 defined as "d[0.1].d"
     And the traversal of
       """
-      g.addE("knows").from(v1).to(v6).property("weight", dotOne)
+      g.addE("knows").from(v1).to(v6).property("weight", xx1)
       """
     When iterated to list
     Then the result should have a count of 1
@@ -380,10 +405,10 @@
       """
     And using the parameter v1 defined as "v[marko]"
     And using the parameter v6 defined as "v[peter]"
-    And using the parameter dotOne defined as "d[0.1].d"
+    And using the parameter xx1 defined as "d[0.1].d"
     And the traversal of
       """
-      g.V(v1).addE("knows").to(v6).property("weight", dotOne)
+      g.V(v1).addE("knows").to(v6).property("weight", xx1)
       """
     When iterated to list
     Then the result should have a count of 1
diff --git a/gremlin-test/features/map/AddVertex.feature b/gremlin-test/features/map/AddVertex.feature
index a60fefb..01fc14a 100644
--- a/gremlin-test/features/map/AddVertex.feature
+++ b/gremlin-test/features/map/AddVertex.feature
@@ -34,10 +34,10 @@
         addE("created").from("josh").to("lop").property(T.id, 11).property("weight", 0.4).
         addE("created").from("peter").to("lop").property(T.id, 12).property("weight", 0.2)
       """
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).as("a").addV("animal").property("age", __.select("a").by("age")).property("name", "puppy")
+      g.V(vid1).as("a").addV("animal").property("age", __.select("a").by("age")).property("name", "puppy")
       """
     When iterated to list
     Then the result should have a count of 1
@@ -93,6 +93,31 @@
     Then the result should have a count of 1
     And the graph should return 1 for count of "g.V().has(\"person\",\"name\",\"stephen\")"
 
+  Scenario: g_V_hasLabelXpersonX_propertyXname_nullX
+    Given the empty graph
+    And the graph initializer of
+      """
+      g.addV("person").property(T.id, 1).property("name", "marko").property("age", 29).as("marko").
+        addV("person").property(T.id, 2).property("name", "vadas").property("age", 27).as("vadas").
+        addV("software").property(T.id, 3).property("name", "lop").property("lang", "java").as("lop").
+        addV("person").property(T.id, 4).property("name","josh").property("age", 32).as("josh").
+        addV("software").property(T.id, 5).property("name", "ripple").property("lang", "java").as("ripple").
+        addV("person").property(T.id, 6).property("name", "peter").property("age", 35).as('peter').
+        addE("knows").from("marko").to("vadas").property(T.id, 7).property("weight", 0.5).
+        addE("knows").from("marko").to("josh").property(T.id, 8).property("weight", 1.0).
+        addE("created").from("marko").to("lop").property(T.id, 9).property("weight", 0.4).
+        addE("created").from("josh").to("ripple").property(T.id, 10).property("weight", 1.0).
+        addE("created").from("josh").to("lop").property(T.id, 11).property("weight", 0.4).
+        addE("created").from("peter").to("lop").property(T.id, 12).property("weight", 0.2)
+      """
+    And the traversal of
+      """
+      g.V().hasLabel("person").property("name", null)
+      """
+    When iterated to list
+    Then the result should have a count of 4
+    And the graph should return 2 for count of "g.V().properties(\"name\")"
+
   Scenario: g_addVXpersonX_propertyXsingle_name_stephenX_propertyXsingle_name_stephenmX
     Given the empty graph
     And the graph initializer of
@@ -387,3 +412,22 @@
       | result |
       | name |
 
+  Scenario: g_addVXnullX_propertyXid_nullX
+    Given the empty graph
+    And the traversal of
+      """
+      g.addV(null).property(T.id, null)
+      """
+    When iterated to list
+    Then the result should have a count of 1
+    And the graph should return 1 for count of "g.V().hasLabel(\"vertex\")"
+
+  Scenario: g_addV_propertyXlabel_personX
+    Given the empty graph
+    And the traversal of
+      """
+      g.addV().property(T.label, "person")
+      """
+    When iterated to list
+    Then the result should have a count of 1
+    And the graph should return 1 for count of "g.V().hasLabel(\"person\")"
diff --git a/gremlin-test/features/map/Coalesce.feature b/gremlin-test/features/map/Coalesce.feature
index 3870ee2..06688c0 100644
--- a/gremlin-test/features/map/Coalesce.feature
+++ b/gremlin-test/features/map/Coalesce.feature
@@ -28,10 +28,10 @@
 
   Scenario: g_VX1X_coalesceXoutXknowsX_outXcreatedXX_valuesXnameX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).coalesce(__.out("knows"), __.out("created")).values("name")
+      g.V(vid1).coalesce(__.out("knows"), __.out("created")).values("name")
       """
     When iterated to list
     Then the result should be unordered
@@ -41,10 +41,10 @@
 
   Scenario: g_VX1X_coalesceXoutXcreatedX_outXknowsXX_valuesXnameX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).coalesce(__.out("created"), __.out("knows")).values("name")
+      g.V(vid1).coalesce(__.out("created"), __.out("knows")).values("name")
       """
     When iterated to list
     Then the result should be unordered
diff --git a/gremlin-test/features/map/Constant.feature b/gremlin-test/features/map/Constant.feature
index 9ad8d13..ed25b25 100644
--- a/gremlin-test/features/map/Constant.feature
+++ b/gremlin-test/features/map/Constant.feature
@@ -19,7 +19,6 @@
 
   Scenario: g_V_constantX123X
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
     And the traversal of
       """
       g.V().constant(123)
@@ -34,6 +33,22 @@
       | d[123].i |
       | d[123].i |
 
+  Scenario: g_V_constantXnullX
+    Given the modern graph
+    And the traversal of
+      """
+      g.V().constant(null)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | null |
+      | null |
+      | null |
+      | null |
+      | null |
+      | null |
+
   Scenario: g_V_chooseXhasLabelXpersonX_valuesXnameX_constantXinhumanXX
     Given the modern graph
     And the traversal of
diff --git a/gremlin-test/features/map/ElementMap.feature b/gremlin-test/features/map/ElementMap.feature
index 95de688..45720ac 100644
--- a/gremlin-test/features/map/ElementMap.feature
+++ b/gremlin-test/features/map/ElementMap.feature
@@ -51,10 +51,10 @@
 
   Scenario: g_EX11X_elementMap
     Given the modern graph
-    And using the parameter e11Id defined as "e[josh-created->lop].id"
+    And using the parameter eid11 defined as "e[josh-created->lop].id"
     And the traversal of
     """
-      g.E(e11Id).elementMap()
+      g.E(eid11).elementMap()
       """
     When iterated to list
     Then the result should be unordered
diff --git a/gremlin-test/features/map/Graph.feature b/gremlin-test/features/map/Graph.feature
index 249d6a3..d3e0fff 100644
--- a/gremlin-test/features/map/Graph.feature
+++ b/gremlin-test/features/map/Graph.feature
@@ -19,10 +19,10 @@
 
   Scenario: g_VX1X_V_valuesXnameX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).V().values("name")
+      g.V(vid1).V().values("name")
       """
     When iterated to list
     Then the result should be unordered
@@ -36,7 +36,6 @@
 
   Scenario: g_V_outXknowsX_V_name
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
     And the traversal of
       """
       g.V().out("knows").V().values("name")
@@ -87,23 +86,23 @@
         addE("created").from("josh").to("lop").property(T.id, 11).property("weight", 0.4).
         addE("created").from("peter").to("lop").property(T.id, 12).property("weight", 0.2)
       """
-    And using the parameter software defined as "l[v[lop],v[ripple]]"
-    And using the parameter v1Id defined as "v[marko].id"
-    And using the parameter v2Id defined as "v[vadas].id"
-    And using the parameter v3Id defined as "v[lop].id"
-    And using the parameter v4Id defined as "v[josh].id"
-    And using the parameter v5Id defined as "v[ripple].id"
-    And using the parameter v6Id defined as "v[peter].id"
+    And using the parameter xx1 defined as "l[v[lop],v[ripple]]"
+    And using the parameter vid1 defined as "v[marko].id"
+    And using the parameter vid2 defined as "v[vadas].id"
+    And using the parameter vid3 defined as "v[lop].id"
+    And using the parameter vid4 defined as "v[josh].id"
+    And using the parameter vid5 defined as "v[ripple].id"
+    And using the parameter vid6 defined as "v[peter].id"
     And the traversal of
       """
-      g.V().hasLabel("person").as("p").V(software).addE("uses").from("p")
+      g.V().hasLabel("person").as("p").V(xx1).addE("uses").from("p")
       """
     When iterated to list
     Then the result should have a count of 8
     And the graph should return 8 for count of "g.E().hasLabel(\"uses\")"
-    And the graph should return 2 for count of "g.V(v1Id).outE(\"uses\")"
-    And the graph should return 2 for count of "g.V(v2Id).outE(\"uses\")"
-    And the graph should return 4 for count of "g.V(v3Id).inE(\"uses\")"
-    And the graph should return 2 for count of "g.V(v4Id).outE(\"uses\")"
-    And the graph should return 4 for count of "g.V(v5Id).inE(\"uses\")"
-    And the graph should return 2 for count of "g.V(v6Id).outE(\"uses\")"
+    And the graph should return 2 for count of "g.V(vid1).outE(\"uses\")"
+    And the graph should return 2 for count of "g.V(vid2).outE(\"uses\")"
+    And the graph should return 4 for count of "g.V(vid3).inE(\"uses\")"
+    And the graph should return 2 for count of "g.V(vid4).outE(\"uses\")"
+    And the graph should return 4 for count of "g.V(vid5).inE(\"uses\")"
+    And the graph should return 2 for count of "g.V(vid6).outE(\"uses\")"
diff --git a/gremlin-test/features/map/Loops.feature b/gremlin-test/features/map/Loops.feature
index b8a70ae..d1c0b9e 100644
--- a/gremlin-test/features/map/Loops.feature
+++ b/gremlin-test/features/map/Loops.feature
@@ -19,10 +19,10 @@
 
   Scenario: g_VX1X_repeatXboth_simplePathX_untilXhasXname_peterX_or_loops_isX3XX_hasXname_peterX_path_byXnameX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).repeat(__.both().simplePath()).until(__.has("name", "peter").or().loops().is(3)).has("name", "peter").path().by("name")
+      g.V(vid1).repeat(__.both().simplePath()).until(__.has("name", "peter").or().loops().is(3)).has("name", "peter").path().by("name")
       """
     When iterated to list
     Then the result should be unordered
@@ -32,10 +32,10 @@
 
   Scenario: g_VX1X_repeatXboth_simplePathX_untilXhasXname_peterX_or_loops_isX2XX_hasXname_peterX_path_byXnameX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).repeat(__.both().simplePath()).until(__.has("name", "peter").or().loops().is(2)).has("name", "peter").path().by("name")
+      g.V(vid1).repeat(__.both().simplePath()).until(__.has("name", "peter").or().loops().is(2)).has("name", "peter").path().by("name")
       """
     When iterated to list
     Then the result should be unordered
@@ -44,10 +44,10 @@
 
   Scenario: g_VX1X_repeatXboth_simplePathX_untilXhasXname_peterX_and_loops_isX3XX_hasXname_peterX_path_byXnameX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).repeat(__.both().simplePath()).until(__.has("name", "peter").and().loops().is(3)).has("name", "peter").path().by("name")
+      g.V(vid1).repeat(__.both().simplePath()).until(__.has("name", "peter").and().loops().is(3)).has("name", "peter").path().by("name")
       """
     When iterated to list
     Then the result should be unordered
diff --git a/gremlin-test/features/map/Map.feature b/gremlin-test/features/map/Map.feature
index 8d1029f..d9acfed 100644
--- a/gremlin-test/features/map/Map.feature
+++ b/gremlin-test/features/map/Map.feature
@@ -19,11 +19,11 @@
 
   Scenario: g_VX1X_mapXnameX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
-    And using the parameter l defined as "c[it.get().value('name')]"
+    And using the parameter vid1 defined as "v[marko].id"
+    And using the parameter l1 defined as "c[it.get().value('name')]"
     And the traversal of
       """
-      g.V(v1Id).map(l)
+      g.V(vid1).map(l1)
       """
     When iterated to list
     Then the result should be unordered
@@ -32,11 +32,11 @@
 
   Scenario: g_VX1X_outE_label_mapXlengthX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
-    And using the parameter l defined as "c[it.get().length()]"
+    And using the parameter vid1 defined as "v[marko].id"
+    And using the parameter l1 defined as "c[it.get().length()]"
     And the traversal of
       """
-      g.V(v1Id).outE().label().map(l)
+      g.V(vid1).outE().label().map(l1)
       """
     When iterated to list
     Then the result should be unordered
@@ -47,12 +47,26 @@
 
   Scenario: g_VX1X_out_mapXnameX_mapXlengthX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And using the parameter l1 defined as "c[it.get().value('name')]"
     And using the parameter l2 defined as "c[it.get().toString().length()]"
     And the traversal of
       """
-      g.V(v1Id).out().map(l1).map(l2)
+      g.V(vid1).out().map(l1).map(l2)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | d[3].i |
+      | d[5].i |
+      | d[4].i |
+
+  Scenario: g_VX1X_out_mapXlambdaXnameXX_mapXlambdaXlengthXX
+    Given the modern graph
+    And using the parameter vid1 defined as "v[marko].id"
+    And the traversal of
+      """
+      g.V(vid1).out().map(Lambda.function("it.get().value('name')")).map(Lambda.function("it.get().toString().length()"))
       """
     When iterated to list
     Then the result should be unordered
@@ -63,10 +77,10 @@
 
   Scenario: g_withPath_V_asXaX_out_mapXa_nameX
     Given the modern graph
-    And using the parameter l defined as "c[it.path('a').value('name')]"
+    And using the parameter l1 defined as "c[it.path('a').value('name')]"
     And the traversal of
       """
-      g.withPath().V().as("a").out().map(l)
+      g.withPath().V().as("a").out().map(l1)
       """
     When iterated to list
     Then the result should be unordered
@@ -80,10 +94,10 @@
 
   Scenario: g_withPath_V_asXaX_out_out_mapXa_name_it_nameX
     Given the modern graph
-    And using the parameter l defined as "c[it.path('a').value('name')  + it.get().value('name')]"
+    And using the parameter l1 defined as "c[it.path('a').value('name')  + it.get().value('name')]"
     And the traversal of
       """
-      g.withPath().V().as("a").out().out().map(l)
+      g.withPath().V().as("a").out().out().map(l1)
       """
     When iterated to list
     Then the result should be unordered
@@ -106,3 +120,19 @@
       | v[josh] |
       | v[ripple] |
       | v[peter]  |
+
+  Scenario: g_V_mapXconstantXnullXX
+    Given the modern graph
+    And the traversal of
+      """
+      g.V().map(__.constant(null))
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | null |
+      | null |
+      | null |
+      | null |
+      | null |
+      | null |
\ No newline at end of file
diff --git a/gremlin-test/features/map/Match.feature b/gremlin-test/features/map/Match.feature
index d0dee12..fc60608 100644
--- a/gremlin-test/features/map/Match.feature
+++ b/gremlin-test/features/map/Match.feature
@@ -540,3 +540,14 @@
       | m[{"a":"v[Garcia]","b":"v[CRYPTICAL ENVELOPMENT]","c":"v[THE OTHER ONE]","d":"v[Weir]"}] |
       | m[{"a":"v[Garcia]","b":"v[CRYPTICAL ENVELOPMENT]","c":"v[WHARF RAT]","d":"v[Hunter]"}] |
 
+  Scenario: g_V_matchXa_outXknowsX_name_bX_identity
+    Given the modern graph
+    And the traversal of
+      """
+      g.V().match(__.as("a").out("knows").values("name").as("b")).identity()
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | m[{"a":"v[marko]","b":"vadas"}] |
+      | m[{"a":"v[marko]","b":"josh"}] |
\ No newline at end of file
diff --git a/gremlin-test/features/map/Math.feature b/gremlin-test/features/map/Math.feature
index 5216241..64ba078 100644
--- a/gremlin-test/features/map/Math.feature
+++ b/gremlin-test/features/map/Math.feature
@@ -61,10 +61,10 @@
 
   Scenario: g_withSideEffectXx_100X_V_age_mathX__plus_xX
     Given the modern graph
-    And using the parameter x defined as "d[100].i"
+    And using the parameter xx1 defined as "d[100].i"
     And the traversal of
       """
-      g.withSideEffect("x", 100).V().values("age").math("_ + x")
+      g.withSideEffect("x", xx1).V().values("age").math("_ + x")
       """
     When iterated to list
     Then the result should be unordered
diff --git a/gremlin-test/features/map/Min.feature b/gremlin-test/features/map/Min.feature
index d15eff7..ad866ec 100644
--- a/gremlin-test/features/map/Min.feature
+++ b/gremlin-test/features/map/Min.feature
@@ -103,10 +103,10 @@
 
   Scenario: g_V_foo_injectX9999999999X_min
     Given the modern graph
-    And using the parameter injectVal defined as "d[9999999999].l"
+    And using the parameter xx1 defined as "d[9999999999].l"
     And the traversal of
       """
-      g.V().values("foo").inject(injectVal).min()
+      g.V().values("foo").inject(xx1).min()
       """
     When iterated to list
     Then the result should be unordered
diff --git a/gremlin-test/features/map/Order.feature b/gremlin-test/features/map/Order.feature
index 6a06890..e208e85 100644
--- a/gremlin-test/features/map/Order.feature
+++ b/gremlin-test/features/map/Order.feature
@@ -35,11 +35,11 @@
 
   Scenario: g_V_name_order_byXa1_b1X_byXb2_a2X
     Given the modern graph
-    And using the parameter l1 defined as "c[a, b -> a.substring(1, 2).compareTo(b.substring(1, 2))]"
-    And using the parameter l2 defined as "c[a, b -> b.substring(2, 3).compareTo(a.substring(2, 3))]"
+    And using the parameter c1 defined as "c[a, b -> a.substring(1, 2).compareTo(b.substring(1, 2))]"
+    And using the parameter c2 defined as "c[a, b -> b.substring(2, 3).compareTo(a.substring(2, 3))]"
     And the traversal of
       """
-      g.V().values("name").order().by(l1).by(l2)
+      g.V().values("name").order().by(c1).by(c2)
       """
     When iterated to list
     Then the result should be ordered
@@ -51,22 +51,6 @@
       | josh   |
       | lop    |
 
-  Scenario: g_V_order_byXname_incrX_name
-    Given the modern graph
-    And the traversal of
-      """
-      g.V().order().by("name", Order.incr).values("name")
-      """
-    When iterated to list
-    Then the result should be ordered
-      | result |
-      | josh |
-      | lop  |
-      | marko |
-      | peter |
-      | ripple |
-      | vadas  |
-
   Scenario: g_V_order_byXname_ascX_name
     Given the modern graph
     And the traversal of
@@ -99,22 +83,6 @@
       | ripple |
       | vadas  |
 
-  Scenario: g_V_outE_order_byXweight_decrX_weight
-    Given the modern graph
-    And the traversal of
-      """
-      g.V().outE().order().by("weight", Order.decr).values("weight")
-      """
-    When iterated to list
-    Then the result should be ordered
-      | result |
-      | d[1.0].d |
-      | d[1.0].d |
-      | d[0.5].d |
-      | d[0.4].d |
-      | d[0.4].d |
-      | d[0.2].d |
-
   Scenario: g_V_outE_order_byXweight_descX_weight
     Given the modern graph
     And the traversal of
@@ -133,11 +101,11 @@
 
   Scenario: g_V_order_byXname_a1_b1X_byXname_b2_a2X_name
     Given the modern graph
-    And using the parameter l1 defined as "c[a, b -> a.substring(1, 2).compareTo(b.substring(1, 2))]"
-    And using the parameter l2 defined as "c[a, b -> b.substring(2, 3).compareTo(a.substring(2, 3))]"
+    And using the parameter c1 defined as "c[a, b -> a.substring(1, 2).compareTo(b.substring(1, 2))]"
+    And using the parameter c2 defined as "c[a, b -> b.substring(2, 3).compareTo(a.substring(2, 3))]"
     And the traversal of
       """
-      g.V().order().by("name", l1).by("name", l2).values("name")
+      g.V().order().by("name", c1).by("name", c2).values("name")
       """
     When iterated to list
     Then the result should be ordered
@@ -370,10 +338,10 @@
 
   Scenario: g_VX1X_elementMap_orderXlocalX_byXkeys_descXunfold
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).elementMap().order(Scope.local).by(Column.keys, Order.desc).unfold()
+      g.V(vid1).elementMap().order(Scope.local).by(Column.keys, Order.desc).unfold()
       """
     When iterated to list
     Then the result should be ordered
diff --git a/gremlin-test/features/map/PageRank.feature b/gremlin-test/features/map/PageRank.feature
index fa5aaf6..479a309 100644
--- a/gremlin-test/features/map/PageRank.feature
+++ b/gremlin-test/features/map/PageRank.feature
@@ -34,11 +34,11 @@
       | v[peter] |
     And the graph should return 6 for count of "g.withComputer().V().pageRank().has(\"gremlin.pageRankVertexProgram.pageRank\")"
 
-  Scenario: g_V_outXcreatedX_pageRank_byXbothEX_byXprojectRankX_timesX0X_valueMapXname_projectRankX
+  Scenario: g_V_outXcreatedX_pageRank_withXedges_bothEX_withXpropertyName_projectRankX_withXtimes_0X_valueMapXname_projectRankX
     Given the modern graph
     And the traversal of
       """
-      g.withComputer().V().out("created").pageRank().by(__.bothE()).by("projectRank").times(0).valueMap("name", "projectRank")
+      g.withComputer().V().out("created").pageRank().with("~tinkerpop.pageRank.edges",__.bothE()).with("~tinkerpop.pageRank.propertyName","projectRank").with("~tinkerpop.pageRank.times",0).valueMap("name", "projectRank")
       """
     When iterated to list
     Then the result should be unordered
@@ -48,11 +48,11 @@
       | m[{"name": ["lop"], "projectRank": [3.0]}] |
       | m[{"name": ["ripple"], "projectRank": [1.0]}] |
 
-  Scenario: g_V_pageRank_order_byXpageRank_decrX_byXnameX_name
+  Scenario: g_V_pageRank_order_byXpageRank_descX_byXnameX_name
     Given the modern graph
     And the traversal of
       """
-      g.withComputer().V().pageRank().order().by("gremlin.pageRankVertexProgram.pageRank", Order.decr).by("name").values("name")
+      g.withComputer().V().pageRank().order().by("gremlin.pageRankVertexProgram.pageRank", Order.desc).by("name").values("name")
       """
     When iterated to list
     Then the result should be ordered
@@ -64,11 +64,11 @@
       | marko  |
       | peter  |
 
-  Scenario: g_V_pageRank_order_byXpageRank_decrX_name_limitX2X
+  Scenario: g_V_pageRank_order_byXpageRank_descX_name_limitX2X
     Given the modern graph
     And the traversal of
       """
-      g.withComputer().V().pageRank().order().by("gremlin.pageRankVertexProgram.pageRank", Order.decr).values("name").limit(2)
+      g.withComputer().V().pageRank().order().by("gremlin.pageRankVertexProgram.pageRank", Order.desc).values("name").limit(2)
       """
     When iterated to list
     Then the result should be ordered
@@ -76,11 +76,11 @@
       | lop    |
       | ripple |
 
-  Scenario: g_V_pageRank_byXoutEXknowsXX_byXfriendRankX_project_byXnameX_byXvaluesXfriendRankX_mathX
+  Scenario: g_V_pageRank_withXedges_outEXknowsXX_withXpropertyName_friendRankX_project_byXnameX_byXvaluesXfriendRankX_mathX
     Given the modern graph
     And the traversal of
       """
-      g.withComputer().V().pageRank().by(__.outE("knows")).by("friendRank").project("name", "friendRank").by("name").by(__.values("friendRank").math("ceil(_ * 100)"))
+      g.withComputer().V().pageRank().with("~tinkerpop.pageRank.edges",__.outE("knows")).with("~tinkerpop.pageRank.propertyName","friendRank").project("name", "friendRank").by("name").by(__.values("friendRank").math("ceil(_ * 100)"))
       """
     When iterated to list
     Then the result should be unordered
@@ -92,11 +92,11 @@
       | m[{"name": "ripple", "friendRank": 15.0}] |
       | m[{"name": "peter", "friendRank": 15.0}] |
 
-  Scenario: g_V_hasLabelXpersonX_pageRank_byXpageRankX_project_byXnameX_byXvaluesXpageRankX_mathX
+  Scenario: g_V_hasLabelXpersonX_pageRank_withXpropertyName_kpageRankX_project_byXnameX_byXvaluesXpageRankX_mathX
     Given the modern graph
     And the traversal of
       """
-      g.withComputer().V().hasLabel("person").pageRank().by("pageRank").project("name", "pageRank").by("name").by(__.values("pageRank").math("ceil(_ * 100)"))
+      g.withComputer().V().hasLabel("person").pageRank().with("~tinkerpop.pageRank.propertyName","pageRank").project("name", "pageRank").by("name").by(__.values("pageRank").math("ceil(_ * 100)"))
       """
     When iterated to list
     Then the result should be unordered
@@ -106,11 +106,11 @@
       | m[{"name": "josh", "pageRank": 59.0}] |
       | m[{"name": "peter", "pageRank": 46.0}] |
 
-  Scenario: g_V_pageRank_byXpageRankX_asXaX_outXknowsX_pageRank_asXbX_selectXa_bX_by_byXmathX
+  Scenario: g_V_pageRank_withXpropertyName_pageRankX_asXaX_outXknowsX_pageRank_asXbX_selectXa_bX_by_byXmathX
     Given the modern graph
     And the traversal of
       """
-      g.withComputer().V().pageRank().by("pageRank").as("a").out("knows").values("pageRank").as("b").select("a", "b").by().by(__.math("ceil(_ * 100)"))
+      g.withComputer().V().pageRank().with("~tinkerpop.pageRank.propertyName","pageRank").as("a").out("knows").values("pageRank").as("b").select("a", "b").by().by(__.math("ceil(_ * 100)"))
       """
     When iterated to list
     Then the result should be unordered
@@ -118,11 +118,11 @@
       | m[{"a": "v[marko]", "b": 15.0}] |
       | m[{"a": "v[marko]", "b": 15.0}] |
 
-  Scenario: g_V_hasLabelXsoftwareX_hasXname_rippleX_pageRankX1X_byXinEXcreatedXX_timesX1X_byXpriorsX_inXcreatedX_unionXboth__identityX_valueMapXname_priorsX
+  Scenario: g_V_hasLabelXsoftwareX_hasXname_rippleX_pageRankX1X_withXedges_inEXcreatedX_withXtimes_1X_withXpropertyName_priorsX_inXcreatedX_unionXboth__identityX_valueMapXname_priorsX
     Given the modern graph
     And the traversal of
       """
-      g.withComputer().V().hasLabel("software").has("name", "ripple").pageRank(1.0).by(__.inE("created")).times(1).by("priors").in("created").union(__.both(), __.identity()).valueMap("name", "priors")
+      g.withComputer().V().hasLabel("software").has("name", "ripple").pageRank(1.0).with("~tinkerpop.pageRank.edges",__.inE("created")).with("~tinkerpop.pageRank.times",1).with("~tinkerpop.pageRank.propertyName","priors").in("created").union(__.both(), __.identity()).valueMap("name", "priors")
       """
     When iterated to list
     Then the result should be unordered
@@ -132,17 +132,11 @@
       | m[{"name": ["lop"], "priors": [0.0]}] |
       | m[{"name": ["ripple"], "priors": [0.0]}] |
 
-  Scenario: g_V_outXcreatedX_groupXmX_byXlabelX_pageRankX1X_byXpageRankX_byXinEX_timesX1X_inXcreatedX_groupXmX_byXpageRankX_capXmX
+  Scenario: g_V_outXcreatedX_groupXmX_byXlabelX_pageRankX1X_withXpropertyName_pageRankX_withXedges_inEX_withXtimes_1X_inXcreatedX_groupXmX_byXpageRankX_capXmX
     Given the modern graph
     And the traversal of
       """
-      g.withComputer().V().out("created").group("m").by(T.label).pageRank(1.0).by("pageRank").by(__.inE()).times(1).in("created").group("m").by("pageRank").cap("m")
+      g.withComputer().V().out("created").group("m").by(T.label).pageRank(1.0).with("~tinkerpop.pageRank.propertyName", "pageRank").with("~tinkerpop.pageRank.edges",__.inE()).with("~tinkerpop.pageRank.times", 1).in("created").group("m").by("pageRank").cap("m")
       """
     When iterated next
-    Then the result should have a count of 3
-
-    # TODO: would really like to have a full assertion here, but withComputer() makes stuff not always return in order.
-    # order could be forced, but that just bulks up the test. we could write better assertion logic but that makes it
-    # harder for GLVs to be tested.  
-    #  | result |
-    #  | m[{"d[1.0].d":"l[v[marko],v[marko],v[marko],v[peter],v[peter],v[peter]]","d[2.0].d":"l[v[josh],v[josh],v[josh],v[josh]]","software":"l[v[lop],v[lop],v[lop],v[ripple]]"}] |
+    Then the result should have a count of 3
\ No newline at end of file
diff --git a/gremlin-test/features/map/Path.feature b/gremlin-test/features/map/Path.feature
index 0bb7573..822358e 100644
--- a/gremlin-test/features/map/Path.feature
+++ b/gremlin-test/features/map/Path.feature
@@ -19,10 +19,10 @@
 
   Scenario: g_VX1X_name_path
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).values("name").path()
+      g.V(vid1).values("name").path()
       """
     When iterated to list
     Then the result should be unordered
@@ -31,10 +31,10 @@
 
   Scenario: g_VX1X_out_path_byXageX_byXnameX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).out().path().by("age").by("name")
+      g.V(vid1).out().path().by("age").by("name")
       """
     When iterated to list
     Then the result should be unordered
@@ -80,10 +80,10 @@
 
   Scenario: g_VX1X_outEXcreatedX_inV_inE_outV_path
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).outE("created").inV().inE().outV().path()
+      g.V(vid1).outE("created").inV().inE().outV().path()
       """
     When iterated to list
     Then the result should be unordered
diff --git a/gremlin-test/features/map/PeerPressure.feature b/gremlin-test/features/map/PeerPressure.feature
index 81ca6f8..4b73300 100644
--- a/gremlin-test/features/map/PeerPressure.feature
+++ b/gremlin-test/features/map/PeerPressure.feature
@@ -34,34 +34,18 @@
       | v[peter] |
     And the graph should return 6 for count of "g.withComputer().V().peerPressure().has(\"gremlin.peerPressureVertexProgram.cluster\")"
 
-  Scenario: g_V_peerPressure_byXclusterX_byXoutEXknowsXX_pageRankX1X_byXrankX_byXoutEXknowsXX_timesX2X_group_byXclusterX_byXrank_sumX_limitX100X
+  Scenario: g_V_peerPressure_withXpropertyName_clusterX_withXedges_outEXknowsXX_pageRankX1X_byXrankX_withXedges_outEXknowsX_withXtimes_2X_group_byXclusterX_byXrank_sumX_limitX100X
     Given the modern graph
     And the traversal of
       """
-      g.withComputer().V().peerPressure().by("cluster").by(__.outE("knows")).pageRank(1.0).by("rank").by(__.outE("knows")).times(1).group().by("cluster").by(__.values("rank").sum()).limit(100)
+      g.withComputer().V().peerPressure().with("~tinkerpop.peerPressure.propertyName","cluster").with("~tinkerpop.peerPressure.edges",__.outE("knows")).pageRank(1.0).with("~tinkerpop.pageRank.propertyName", "rank").with("~tinkerpop.pageRank.edges", __.outE("knows")).with("~tinkerpop.pageRank.times", 1).group().by("cluster").by(__.values("rank").sum()).limit(100)
       """
     When iterated to list
     Then the result should be unordered
       | result |
       | m[{"d[1].i":"d[0.5833333333333333].d","d[3].i":"d[0.1388888888888889].d","d[5].i":"d[0.1388888888888889].d","d[6].i":"d[0.1388888888888889].d"}] |
 
-  Scenario: g_V_hasXname_rippleX_inXcreatedX_peerPressure_byXoutEX_byXclusterX_repeatXunionXidentity__bothX_timesX2X_dedup_valueMapXname_clusterX
-    Given the modern graph
-    And the traversal of
-      """
-      g.withComputer().V().has("name", "ripple").in("created").peerPressure().by(__.outE()).by("cluster").repeat(__.union(__.identity(), __.both())).times(2).dedup().valueMap("name", "cluster")
-      """
-    When iterated to list
-    Then the result should be unordered
-      | result |
-      | m[{"name": ["marko"], "cluster": [1]}] |
-      | m[{"name": ["vadas"], "cluster": [2]}] |
-      | m[{"name": ["lop"], "cluster": [4]}] |
-      | m[{"name": ["josh"], "cluster": [4]}] |
-      | m[{"name": ["ripple"], "cluster": [4]}] |
-      | m[{"name": ["peter"], "cluster": [6]}] |
-
-  Scenario: g_V_hasXname_rippleX_inXcreatedX_peerPressure_withXEDGES_outEX_withXPROPERTY_NAME_clusterX_repeatXunionXidentity__bothX_timesX2X_dedup_valueMapXname_clusterX
+  Scenario: g_V_hasXname_rippleX_inXcreatedX_peerPressure_withXedges_outEX_withyXpropertyName_clusterX_repeatXunionXidentity__bothX_timesX2X_dedup_valueMapXname_clusterX
     Given the modern graph
     And the traversal of
       """
diff --git a/gremlin-test/features/map/Select.feature b/gremlin-test/features/map/Select.feature
index 4a6d5e7..c0002f2 100644
--- a/gremlin-test/features/map/Select.feature
+++ b/gremlin-test/features/map/Select.feature
@@ -19,10 +19,10 @@
 
   Scenario: get_g_VX1X_asXaX_outXknowsX_asXbX_selectXa_bX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).as("a").out("knows").as("b").select("a", "b")
+      g.V(vid1).as("a").out("knows").as("b").select("a", "b")
       """
     When iterated to list
     Then the result should be unordered
@@ -32,10 +32,10 @@
 
   Scenario: g_VX1X_asXaX_outXknowsX_asXbX_selectXa_bX_byXnameX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).as("a").out("knows").as("b").
+      g.V(vid1).as("a").out("knows").as("b").
         select("a", "b").by("name")
       """
     When iterated to list
@@ -46,10 +46,10 @@
 
   Scenario: g_VX1X_asXaX_outXknowsX_asXbX_selectXaX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).as("a").out("knows").as("b").select("a")
+      g.V(vid1).as("a").out("knows").as("b").select("a")
       """
     When iterated to list
     Then the result should be unordered
@@ -59,10 +59,10 @@
 
   Scenario: g_VX1X_asXaX_outXknowsX_asXbX_selectXaX_byXnameX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).as("a").out("knows").as("b").
+      g.V(vid1).as("a").out("knows").as("b").
         select("a").by("name")
       """
     When iterated to list
@@ -185,9 +185,10 @@
 
   Scenario: g_V_chooseXoutE_count_isX0X__asXaX__asXbXX_chooseXselectXaX__selectXaX__selectXbXX
     Given the modern graph
+    And using the parameter xx1 defined as "d[0].l"
     And the traversal of
       """
-      g.V().choose(__.outE().count().is(0L),
+      g.V().choose(__.outE().count().is(xx1),
                    __.as("a"),
                    __.as("b")).
             choose(__.select("a"),
@@ -206,10 +207,10 @@
 
   Scenario: g_VX1X_groupXaX_byXconstantXaXX_byXnameX_selectXaX_selectXaX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).group("a").
+      g.V(vid1).group("a").
                   by(__.constant("a")).
                   by(__.values("name")).
         barrier().
@@ -222,10 +223,10 @@
 
   Scenario: g_VX1X_asXhereX_out_selectXhereX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).as("here").out().select("here")
+      g.V(vid1).as("here").out().select("here")
       """
     When iterated to list
     Then the result should be unordered
@@ -236,10 +237,10 @@
 
   Scenario: g_VX4X_out_asXhereX_hasXlang_javaX_selectXhereX
     Given the modern graph
-    And using the parameter v4Id defined as "v[josh].id"
+    And using the parameter vid4 defined as "v[josh].id"
     And the traversal of
       """
-      g.V(v4Id).as("here").out().select("here")
+      g.V(vid4).as("here").out().select("here")
       """
     When iterated to list
     Then the result should be unordered
@@ -249,10 +250,10 @@
 
   Scenario: g_VX4X_out_asXhereX_hasXlang_javaX_selectXhereX_name
     Given the modern graph
-    And using the parameter v4Id defined as "v[josh].id"
+    And using the parameter vid4 defined as "v[josh].id"
     And the traversal of
       """
-      g.V(v4Id).out().as("here").
+      g.V(vid4).out().as("here").
         has("lang", "java").
         select("here").values("name")
       """
@@ -264,10 +265,10 @@
 
   Scenario: g_VX1X_outE_asXhereX_inV_hasXname_vadasX_selectXhereX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).outE().as("here").
+      g.V(vid1).outE().as("here").
         inV().has("name", "vadas").
         select("here")
       """
@@ -278,10 +279,10 @@
 
   Scenario: g_VX1X_outEXknowsX_hasXweight_1X_asXhereX_inV_hasXname_joshX_selectXhereX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).outE("knows").
+      g.V(vid1).outE("knows").
         has("weight", 1.0).as("here").
         inV().has("name", "josh").
         select("here")
@@ -293,10 +294,10 @@
 
   Scenario: g_VX1X_outEXknowsX_asXhereX_hasXweight_1X_asXfakeX_inV_hasXname_joshX_selectXhereX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).outE("knows").as("here").
+      g.V(vid1).outE("knows").as("here").
         has("weight", 1.0).as("fake").
         inV().has("name", "josh").
         select("here")
@@ -437,10 +438,10 @@
 
   Scenario: g_VX1X_asXaX_outXknowsX_asXbX_selectXa_bX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).as("a").out("knows").as("b").select("a", "b")
+      g.V(vid1).as("a").out("knows").as("b").select("a", "b")
       """
     When iterated to list
     Then the result should be unordered
@@ -461,10 +462,10 @@
 
   Scenario: g_VX1X_asXaX_repeatXout_asXaXX_timesX2X_selectXfirst_aX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).as("a").repeat(__.out().as("a")).times(2).select(Pop.first, "a")
+      g.V(vid1).as("a").repeat(__.out().as("a")).times(2).select(Pop.first, "a")
       """
     When iterated to list
     Then the result should be unordered
@@ -486,10 +487,10 @@
 
   Scenario: g_VX1X_asXaX_repeatXout_asXaXX_timesX2X_selectXlast_aX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).as("a").repeat(__.out().as("a")).times(2).select(Pop.last, "a")
+      g.V(vid1).as("a").repeat(__.out().as("a")).times(2).select(Pop.last, "a")
       """
     When iterated to list
     Then the result should be unordered
@@ -499,10 +500,10 @@
 
   Scenario: g_VX1X_outEXknowsX_asXhereX_hasXweight_1X_inV_hasXname_joshX_selectXhereX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).outE("knows").as("here").has("weight", 1.0).inV().has("name", "josh").select("here")
+      g.V(vid1).outE("knows").as("here").has("weight", 1.0).inV().has("name", "josh").select("here")
       """
     When iterated to list
     Then the result should be unordered
@@ -790,4 +791,27 @@
     Then the result should be unordered
       | result |
       | v[marko] |
-      | v[marko] |
\ No newline at end of file
+      | v[marko] |
+  Scenario: g_EX11X_propertiesXweightX_asXaX_selectXaX_byXkeyX
+    Given the modern graph
+    And using the parameter eid11 defined as "e[josh-created->lop].id"
+    And the traversal of
+      """
+      g.E(eid11).properties("weight").as("a").select("a").by(T.key)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | weight |
+
+  Scenario: g_EX11X_propertiesXweightX_asXaX_selectXaX_byXvalueX
+    Given the modern graph
+    And using the parameter eid11 defined as "e[josh-created->lop].id"
+    And the traversal of
+      """
+      g.E(eid11).properties("weight").as("a").select("a").by(T.value)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | d[0.4].d |
\ No newline at end of file
diff --git a/gremlin-test/features/map/Unfold.feature b/gremlin-test/features/map/Unfold.feature
index 3a20d08..5360471 100644
--- a/gremlin-test/features/map/Unfold.feature
+++ b/gremlin-test/features/map/Unfold.feature
@@ -35,10 +35,10 @@
 
   Scenario: g_V_valueMap_unfold_mapXkeyX
     Given the modern graph
-    And using the parameter l defined as "c[it.get().getKey()]"
+    And using the parameter l1 defined as "c[it.get().getKey()]"
     And the traversal of
       """
-      g.V().valueMap().unfold().map(l)
+      g.V().valueMap().unfold().map(l1)
       """
     When iterated to list
     Then the result should be unordered
@@ -58,11 +58,11 @@
 
   Scenario: g_VX1X_repeatXboth_simplePathX_untilXhasIdX6XX_path_byXnameX_unfold
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
-    And using the parameter v6Id defined as "v[peter].id"
+    And using the parameter vid1 defined as "v[marko].id"
+    And using the parameter vid6 defined as "v[peter].id"
     And the traversal of
       """
-      g.V(v1Id).repeat(__.both().simplePath()).until(__.hasId(v6Id)).path().by("name").unfold()
+      g.V(vid1).repeat(__.both().simplePath()).until(__.hasId(vid6)).path().by("name").unfold()
       """
     When iterated to list
     Then the result should be unordered
diff --git a/gremlin-test/features/map/ValueMap.feature b/gremlin-test/features/map/ValueMap.feature
index b7f99f8..9818a96 100644
--- a/gremlin-test/features/map/ValueMap.feature
+++ b/gremlin-test/features/map/ValueMap.feature
@@ -147,10 +147,10 @@
 
   Scenario: g_VX1X_outXcreatedX_valueMap
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).out("created").valueMap()
+      g.V(vid1).out("created").valueMap()
       """
     When iterated to list
     Then the result should be unordered
@@ -185,10 +185,10 @@
 
   Scenario: g_VX1X_valueMapXname_locationX_byXunfoldX_by
     Given the crew graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).valueMap("name", "location").by(__.unfold()).by()
+      g.V(vid1).valueMap("name", "location").by(__.unfold()).by()
       """
     When iterated to list
     Then the result should be unordered
diff --git a/gremlin-test/features/map/Vertex.feature b/gremlin-test/features/map/Vertex.feature
index ea32638..62ac798 100644
--- a/gremlin-test/features/map/Vertex.feature
+++ b/gremlin-test/features/map/Vertex.feature
@@ -19,10 +19,10 @@
 
   Scenario: g_VXlistX1_2_3XX_name
     Given the modern graph
-    And using the parameter vx defined as "l[v[marko].id,v[vadas].id,v[lop].id]"
+    And using the parameter xx1 defined as "l[v[marko].id,v[vadas].id,v[lop].id]"
     And the traversal of
       """
-      g.V(vx).values("name")
+      g.V(xx1).values("name")
       """
     When iterated to list
     Then the result should be unordered
@@ -33,10 +33,10 @@
 
   Scenario: g_VXlistXv1_v2_v3XX_name
     Given the modern graph
-    And using the parameter vx defined as "l[v[marko],v[vadas],v[lop]]"
+    And using the parameter xx1 defined as "l[v[marko],v[vadas],v[lop]]"
     And the traversal of
       """
-      g.V(vx).values("name")
+      g.V(xx1).values("name")
       """
     When iterated to list
     Then the result should be unordered
@@ -77,10 +77,10 @@
 
   Scenario: g_VX1X_out
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).out()
+      g.V(vid1).out()
       """
     When iterated to list
     Then the result should be unordered
@@ -91,10 +91,10 @@
 
   Scenario: g_VX2X_in
     Given the modern graph
-    And using the parameter v2Id defined as "v[vadas].id"
+    And using the parameter vid2 defined as "v[vadas].id"
     And the traversal of
       """
-      g.V(v2Id).in()
+      g.V(vid2).in()
       """
     When iterated to list
     Then the result should be unordered
@@ -103,10 +103,10 @@
 
   Scenario: g_VX4X_both
     Given the modern graph
-    And using the parameter v4Id defined as "v[josh].id"
+    And using the parameter vid4 defined as "v[josh].id"
     And the traversal of
       """
-      g.V(v4Id).both()
+      g.V(vid4).both()
       """
     When iterated to list
     Then the result should be unordered
@@ -133,10 +133,10 @@
 
   Scenario: g_EX11X
     Given the modern graph
-    And using the parameter e11Id defined as "e[josh-created->lop].id"
+    And using the parameter eid11 defined as "e[josh-created->lop].id"
     And the traversal of
     """
-      g.E(e11Id)
+      g.E(eid11)
       """
     When iterated to list
     Then the result should be unordered
@@ -145,10 +145,10 @@
 
   Scenario: g_EX11AsStringX
     Given the modern graph
-    And using the parameter e11Id defined as "e[josh-created->lop].sid"
+    And using the parameter eid11 defined as "e[josh-created->lop].sid"
     And the traversal of
     """
-      g.E(e11Id)
+      g.E(eid11)
       """
     When iterated to list
     Then the result should be unordered
@@ -183,10 +183,10 @@
 
   Scenario: g_EXlistXe7_e11XX
     Given the modern graph
-    And using the parameter l defined as "l[e[marko-knows->vadas],e[josh-created->lop]]"
+    And using the parameter xx1 defined as "l[e[marko-knows->vadas],e[josh-created->lop]]"
     And the traversal of
     """
-      g.E(l)
+      g.E(xx1)
       """
     When iterated to list
     Then the result should be unordered
@@ -196,10 +196,10 @@
 
   Scenario: g_VX1X_outE
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
     """
-      g.V(v1Id).outE()
+      g.V(vid1).outE()
       """
     When iterated to list
     Then the result should be unordered
@@ -210,10 +210,10 @@
 
   Scenario: g_VX2X_outE
     Given the modern graph
-    And using the parameter v2Id defined as "v[vadas].id"
+    And using the parameter vid2 defined as "v[vadas].id"
     And the traversal of
     """
-      g.V(v2Id).inE()
+      g.V(vid2).inE()
       """
     When iterated to list
     Then the result should be unordered
@@ -222,10 +222,10 @@
 
   Scenario: g_VX4X_bothEXcreatedX
     Given the modern graph
-    And using the parameter v4Id defined as "v[josh].id"
+    And using the parameter vid4 defined as "v[josh].id"
     And the traversal of
     """
-      g.V(v4Id).bothE("created")
+      g.V(vid4).bothE("created")
       """
     When iterated to list
     Then the result should be unordered
@@ -235,10 +235,10 @@
 
   Scenario: g_VX4X_bothE
     Given the modern graph
-    And using the parameter v4Id defined as "v[josh].id"
+    And using the parameter vid4 defined as "v[josh].id"
     And the traversal of
     """
-      g.V(v4Id).bothE()
+      g.V(vid4).bothE()
       """
     When iterated to list
     Then the result should be unordered
@@ -249,10 +249,10 @@
 
   Scenario: g_VX1X_outE_inV
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).both()
+      g.V(vid1).both()
       """
     When iterated to list
     Then the result should be unordered
@@ -263,10 +263,10 @@
 
   Scenario: g_VX2X_inE_outV
     Given the modern graph
-    And using the parameter v2Id defined as "v[vadas].id"
+    And using the parameter vid2 defined as "v[vadas].id"
     And the traversal of
       """
-      g.V(v2Id).inE().outV()
+      g.V(vid2).inE().outV()
       """
     When iterated to list
     Then the result should be unordered
@@ -307,10 +307,10 @@
 
   Scenario: g_VX1X_outEXknowsX_bothV_name
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).outE("knows").bothV().values("name")
+      g.V(vid1).outE("knows").bothV().values("name")
       """
     When iterated to list
     Then the result should be unordered
@@ -322,10 +322,10 @@
 
   Scenario: g_VX1X_outE_otherV
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).outE().otherV()
+      g.V(vid1).outE().otherV()
       """
     When iterated to list
     Then the result should be unordered
@@ -336,10 +336,10 @@
 
   Scenario: g_VX4X_bothE_otherV
     Given the modern graph
-    And using the parameter v4Id defined as "v[josh].id"
+    And using the parameter vid4 defined as "v[josh].id"
     And the traversal of
       """
-      g.V(v4Id).bothE().otherV()
+      g.V(vid4).bothE().otherV()
       """
     When iterated to list
     Then the result should be unordered
@@ -350,10 +350,10 @@
 
   Scenario: g_VX4X_bothE_hasXweight_lt_1X_otherV
     Given the modern graph
-    And using the parameter v4Id defined as "v[josh].id"
+    And using the parameter vid4 defined as "v[josh].id"
     And the traversal of
       """
-      g.V(v4Id).bothE().has("weight", P.lt(1.0)).otherV()
+      g.V(vid4).bothE().has("weight", P.lt(1.0)).otherV()
       """
     When iterated to list
     Then the result should be unordered
@@ -362,10 +362,10 @@
 
   Scenario: g_VX2X_inE
     Given the modern graph
-    And using the parameter v2Id defined as "v[vadas].id"
+    And using the parameter vid2 defined as "v[vadas].id"
     And the traversal of
     """
-      g.V(v2Id).bothE()
+      g.V(vid2).bothE()
       """
     When iterated to list
     Then the result should be unordered
@@ -374,10 +374,10 @@
 
   Scenario: get_g_VX1X_outE_otherV
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).outE().otherV()
+      g.V(vid1).outE().otherV()
       """
     When iterated to list
     Then the result should be unordered
@@ -388,10 +388,10 @@
 
   Scenario: g_VX1X_outXknowsX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).out("knows")
+      g.V(vid1).out("knows")
       """
     When iterated to list
     Then the result should be unordered
@@ -401,10 +401,10 @@
 
   Scenario: g_VX1AsStringX_outXknowsX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].sid"
+    And using the parameter vid1 defined as "v[marko].sid"
     And the traversal of
       """
-      g.V(v1Id).out("knows")
+      g.V(vid1).out("knows")
       """
     When iterated to list
     Then the result should be unordered
@@ -414,10 +414,10 @@
 
   Scenario: g_VX1X_outXknows_createdX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).out("knows","created")
+      g.V(vid1).out("knows","created")
       """
     When iterated to list
     Then the result should be unordered
@@ -428,10 +428,10 @@
 
   Scenario: g_VX1X_outEXknowsX_inV
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).outE("knows").inV()
+      g.V(vid1).outE("knows").inV()
       """
     When iterated to list
     Then the result should be unordered
@@ -441,10 +441,10 @@
 
   Scenario: g_VX1X_outEXknows_createdX_inV
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).outE("knows","created").inV()
+      g.V(vid1).outE("knows","created").inV()
       """
     When iterated to list
     Then the result should be unordered
@@ -467,20 +467,20 @@
 
   Scenario: g_VX1X_out_out_out
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).out().out().out()
+      g.V(vid1).out().out().out()
       """
     When iterated to list
     Then the result should be empty
 
   Scenario: g_VX1X_out_name
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).out().values("name")
+      g.V(vid1).out().values("name")
       """
     When iterated to list
     Then the result should be unordered
@@ -491,10 +491,10 @@
 
   Scenario: g_VX1X_to_XOUT_knowsX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).to(Direction.OUT, "knows")
+      g.V(vid1).to(Direction.OUT, "knows")
       """
     When iterated to list
     Then the result should be unordered
@@ -507,13 +507,13 @@
   # which is simulated by an edge identifier.
   Scenario: g_VX1_2_3_4X_name
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
-    And using the parameter v2Id defined as "v[vadas].id"
-    And using the parameter v3Id defined as "e[marko-knows->josh].id"
-    And using the parameter v4Id defined as "v[josh].id"
+    And using the parameter vid1 defined as "v[marko].id"
+    And using the parameter vid2 defined as "v[vadas].id"
+    And using the parameter vid3 defined as "e[marko-knows->josh].id"
+    And using the parameter vid4 defined as "v[josh].id"
     And the traversal of
       """
-      g.V(v1Id, v2Id, v3Id, v4Id).values("name")
+      g.V(vid1, vid2, vid3, vid4).values("name")
       """
     When iterated to list
     Then the result should be unordered
diff --git a/gremlin-test/features/sideEffect/Aggregate.feature b/gremlin-test/features/sideEffect/Aggregate.feature
index 2e80990..38a609a 100644
--- a/gremlin-test/features/sideEffect/Aggregate.feature
+++ b/gremlin-test/features/sideEffect/Aggregate.feature
@@ -113,10 +113,10 @@
 
   Scenario: g_VX1X_aggregateXlocal_aX_byXnameX_out_aggregateXlocal_aX_byXnameX_name_capXaX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).aggregate(Scope.local,"a").by("name").out().aggregate(Scope.local,"a").by("name").values("name").cap("a")
+      g.V(vid1).aggregate(Scope.local,"a").by("name").out().aggregate(Scope.local,"a").by("name").values("name").cap("a")
       """
     When iterated next
     Then the result should be unordered
@@ -128,10 +128,10 @@
 
   Scenario: g_withSideEffectXa_setX_V_both_name_aggregateXlocal_aX_capXaX
     Given the modern graph
-    And using the parameter initial defined as "s[]"
+    And using the parameter xx1 defined as "s[]"
     And the traversal of
       """
-      g.withSideEffect("a", initial).V().both().values("name").aggregate(Scope.local,"a").cap("a")
+      g.withSideEffect("a", xx1).V().both().values("name").aggregate(Scope.local,"a").cap("a")
       """
     When iterated next
     Then the result should be unordered
diff --git a/gremlin-test/features/sideEffect/Group.feature b/gremlin-test/features/sideEffect/Group.feature
index e69b447..a8cf455 100644
--- a/gremlin-test/features/sideEffect/Group.feature
+++ b/gremlin-test/features/sideEffect/Group.feature
@@ -28,6 +28,17 @@
       | result |
       | m[{"ripple":"l[v[ripple]]", "peter":"l[v[peter]]", "vadas":"l[v[vadas]]", "josh": "l[v[josh]]", "lop":"l[v[lop]]", "marko":"l[v[marko]]"}] |
 
+  Scenario: g_V_group_byXageX
+    Given the modern graph
+    And the traversal of
+      """
+      g.V().group().by("age")
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | m[{"null":"l[v[lop],v[ripple]]", "d[35].i":"l[v[peter]]", "d[27].i":"l[v[vadas]]", "d[32].i": "l[v[josh]]", "d[29].i":"l[v[marko]]"}] |
+
   Scenario: g_V_group_byXnameX_by
     Given the modern graph
     And the traversal of
@@ -230,10 +241,10 @@
 
   Scenario: g_withSideEffectXa__marko_666_noone_blahX_V_groupXaX_byXnameX_byXoutE_label_foldX_capXaX
     Given the modern graph
-    And using the parameter m defined as "m[{\"marko\":[666], \"noone\":[\"blah\"]}]"
+    And using the parameter xx1 defined as "m[{\"marko\":[666], \"noone\":[\"blah\"]}]"
     And the traversal of
       """
-      g.withSideEffect("a", m).V().group("a").by("name").by(__.outE().label().fold()).cap("a")
+      g.withSideEffect("a", xx1).V().group("a").by("name").by(__.outE().label().fold()).cap("a")
       """
     When iterated to list
     Then the result should be unordered
@@ -262,3 +273,25 @@
       | result |
       | m[{"ripple":"d[32].l", "lop":"d[96].l"}] |
 
+
+  Scenario: g_V_group_byXlabelX_byXlabel_countX
+    Given the modern graph
+    And the traversal of
+      """
+      g.V().group().by(__.label()).by(__.label().count())
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | m[{"software":"d[2].l", "person":"d[4].l"}] |
+
+  Scenario: g_V_groupXmX_byXlabelX_byXlabel_countX_capXmX
+    Given the modern graph
+    And the traversal of
+      """
+      g.V().group("m").by(__.label()).by(__.label().count()).cap("m")
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | m[{"software":"d[2].l", "person":"d[4].l"}] |
diff --git a/gremlin-test/features/sideEffect/GroupCount.feature b/gremlin-test/features/sideEffect/GroupCount.feature
index 40978cb..53acd6d 100644
--- a/gremlin-test/features/sideEffect/GroupCount.feature
+++ b/gremlin-test/features/sideEffect/GroupCount.feature
@@ -190,4 +190,15 @@
     When iterated to list
     Then the result should be unordered
       | result |
-      | m[{"v[marko]":"d[6].l","v[vadas]":"d[2].l","v[lop]":"d[6].l","v[josh]":"d[6].l","v[ripple]":"d[2].l","v[peter]":"d[2].l"}] |
\ No newline at end of file
+      | m[{"v[marko]":"d[6].l","v[vadas]":"d[2].l","v[lop]":"d[6].l","v[josh]":"d[6].l","v[ripple]":"d[2].l","v[peter]":"d[2].l"}] |
+
+  Scenario: g_V_hasXperson_name_markoX_bothXknowsX_groupCount_byXvaluesXnameX_foldX
+    Given the modern graph
+    And the traversal of
+      """
+      g.V().has("person", "name", "marko").both("knows").groupCount().by(__.values("name").fold())
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | m[{"l[josh]":"d[1].l","l[vadas]":"d[1].l"}] |
\ No newline at end of file
diff --git a/gremlin-test/features/sideEffect/Inject.feature b/gremlin-test/features/sideEffect/Inject.feature
index 740928d..dc5e717 100644
--- a/gremlin-test/features/sideEffect/Inject.feature
+++ b/gremlin-test/features/sideEffect/Inject.feature
@@ -19,11 +19,11 @@
 
   Scenario: g_VX1X_out_injectXv2X_name
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And using the parameter v2 defined as "v[vadas]"
     And the traversal of
       """
-      g.V(v1Id).out().inject(v2).values("name")
+      g.V(vid1).out().inject(v2).values("name")
       """
     When iterated to list
     Then the result should be unordered
@@ -36,11 +36,11 @@
 
   Scenario: g_VX1X_out_name_injectXdanielX_asXaX_mapXlengthX_path
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
-    And using the parameter c defined as "c[it.get().length()]"
+    And using the parameter vid1 defined as "v[marko].id"
+    And using the parameter l1 defined as "c[it.get().length()]"
     And the traversal of
       """
-      g.V(v1Id).out().values("name").inject("daniel").as("a").map(c).path()
+      g.V(vid1).out().values("name").inject("daniel").as("a").map(l1).path()
       """
     When iterated to list
     Then the result should be unordered
@@ -52,11 +52,11 @@
 
   Scenario: g_VX1X_injectXg_VX4XX_out_name
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And using the parameter v4 defined as "v[josh]"
     And the traversal of
       """
-      g.V(v1Id).inject(v4).out().values("name")
+      g.V(vid1).inject(v4).out().values("name")
       """
     When iterated to list
     Then the result should be unordered
@@ -66,3 +66,42 @@
       | lop   |
       | vadas |
       | josh  |
+
+  Scenario: g_injectXnull_1_3_nullX
+    Given the empty graph
+    And the traversal of
+      """
+      g.inject(null, 1, 3, null)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | null |
+      | d[1].i |
+      | d[3].i |
+      | null |
+
+  Scenario: g_injectX10_20_null_20_10_10X_groupCountXxX_dedup_asXyX_projectXa_bX_by_byXselectXxX_selectXselectXyXXX
+    Given the empty graph
+    And the traversal of
+      """
+      g.inject(10,20,null,20,10,10).groupCount("x").dedup().as("y").project("a","b").by().by(__.select("x").select(__.select("y")))
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | m[{"a":"d[10].i", "b":"d[3].l"}] |
+      | m[{"a":"d[20].i", "b":"d[2].l"}] |
+      | m[{"a":null, "b":"d[1].l"}] |
+
+  Scenario: g_injectXname_marko_age_nullX_selectXname_ageX
+    Given the empty graph
+    And using the parameter xx1 defined as "m[{\"name\":\"marko\", \"age\":null}]"
+    And the traversal of
+      """
+      g.inject(xx1).select("name","age")
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | m[{"name":"marko", "age":null}] |
\ No newline at end of file
diff --git a/gremlin-test/features/sideEffect/Sack.feature b/gremlin-test/features/sideEffect/Sack.feature
index 0166934..6c4627d 100644
--- a/gremlin-test/features/sideEffect/Sack.feature
+++ b/gremlin-test/features/sideEffect/Sack.feature
@@ -58,10 +58,10 @@
 
   Scenario: g_withBulkXfalseX_withSackX1_sumX_VX1X_localXoutEXknowsX_barrierXnormSackX_inVX_inXknowsX_barrier_sack
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.withBulk(false).withSack(1.0, Operator.sum).V(v1Id).local(__.outE("knows").barrier(Barrier.normSack).inV()).in("knows").barrier().sack()
+      g.withBulk(false).withSack(1.0, Operator.sum).V(vid1).local(__.outE("knows").barrier(Barrier.normSack).inV()).in("knows").barrier().sack()
       """
     When iterated to list
     Then the result should be unordered
@@ -70,7 +70,6 @@
 
   Scenario: g_withBulkXfalseX_withSackX1_sumX_V_out_barrier_sack
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
     And the traversal of
       """
       g.withBulk(false).withSack(1, Operator.sum).V().out().barrier().sack()
@@ -85,10 +84,10 @@
 
   Scenario: g_withSackX1_sumX_VX1X_localXoutXknowsX_barrierXnormSackXX_inXknowsX_barrier_sack
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.withSack(1.0, Operator.sum).V(v1Id).local(__.out("knows").barrier(Barrier.normSack)).in("knows").barrier().sack()
+      g.withSack(1.0, Operator.sum).V(vid1).local(__.out("knows").barrier(Barrier.normSack)).in("knows").barrier().sack()
       """
     When iterated to list
     Then the result should be unordered
diff --git a/gremlin-test/features/sideEffect/Store.feature b/gremlin-test/features/sideEffect/Store.feature
index f61cbc4..deb1264 100644
--- a/gremlin-test/features/sideEffect/Store.feature
+++ b/gremlin-test/features/sideEffect/Store.feature
@@ -35,10 +35,10 @@
 
   Scenario: g_VX1X_storeXaX_byXnameX_out_storeXaX_byXnameX_name_capXaX
     Given the modern graph
-    And using the parameter v1Id defined as "v[marko].id"
+    And using the parameter vid1 defined as "v[marko].id"
     And the traversal of
       """
-      g.V(v1Id).store("a").by("name").out().store("a").by("name").values("name").cap("a")
+      g.V(vid1).store("a").by("name").out().store("a").by("name").values("name").cap("a")
       """
     When iterated next
     Then the result should be unordered
@@ -50,10 +50,10 @@
 
   Scenario: g_withSideEffectXa_setX_V_both_name_storeXaX_capXaX
     Given the modern graph
-    And using the parameter initial defined as "s[]"
+    And using the parameter xx1 defined as "s[]"
     And the traversal of
       """
-      g.withSideEffect("a", initial).V().both().values("name").store("a").cap("a")
+      g.withSideEffect("a", xx1).V().both().values("name").store("a").cap("a")
       """
     When iterated next
     Then the result should be unordered
diff --git a/gremlin-test/pom.xml b/gremlin-test/pom.xml
index baff056..2b088fd 100644
--- a/gremlin-test/pom.xml
+++ b/gremlin-test/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.apache.tinkerpop</groupId>
         <artifactId>tinkerpop</artifactId>
-        <version>3.4.12-SNAPSHOT</version>
+        <version>3.5.1-SNAPSHOT</version>
     </parent>
     <artifactId>gremlin-test</artifactId>
     <name>Apache TinkerPop :: Gremlin Test</name>
@@ -45,13 +45,18 @@
         </dependency>
         <dependency>
             <groupId>org.hamcrest</groupId>
-            <artifactId>hamcrest-all</artifactId>
+            <artifactId>hamcrest</artifactId>
         </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-log4j12</artifactId>
             <optional>true</optional>
         </dependency>
+        <dependency>
+            <groupId>org.apache.kerby</groupId>
+            <artifactId>kerb-simplekdc</artifactId>
+            <version>2.0.0</version>
+        </dependency>
     </dependencies>
     <build>
         <directory>${basedir}/target</directory>
@@ -77,6 +82,24 @@
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-failsafe-plugin</artifactId>
             </plugin>
+            <plugin>
+                <!--Needed for docker/gremlin-server.sh-->
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <descriptorRefs>
+                        <descriptorRef>jar-with-dependencies</descriptorRef>
+                    </descriptorRefs>
+                </configuration>
+            </plugin>
         </plugins>
     </build>
 
@@ -96,7 +119,7 @@
                         <groupId>org.apache.maven.plugins</groupId>
                         <artifactId>maven-surefire-plugin</artifactId>
                         <configuration>
-                            <argLine>-Dlog4j.configuration=${log4j-test.properties} -Dbuild.dir=${project.build.directory} -Dis.testing=true -Djava.net.preferIPv4Stack=true
+                            <argLine>-Dlog4j.configuration=${log4j-test.properties} -Dbuild.dir=${project.build.directory} -Dis.testing=true -Djava.net.preferIPv4Stack=true ${suresafeArgs}
                             </argLine>
                             <excludes>
                                 <exclude>TraversalInterruptionTest.java</exclude>
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/AbstractFileGraphProvider.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/AbstractFileGraphProvider.java
index 18e9a0d..cedbf38 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/AbstractFileGraphProvider.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/AbstractFileGraphProvider.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.structure.Graph;
 import org.apache.tinkerpop.gremlin.structure.io.Storage;
 import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONResourceAccess;
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/AbstractGraphProvider.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/AbstractGraphProvider.java
index b9c5038..47c8e43 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/AbstractGraphProvider.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/AbstractGraphProvider.java
@@ -23,8 +23,8 @@
 import org.apache.tinkerpop.gremlin.structure.io.IoRegistry;
 import org.apache.tinkerpop.gremlin.structure.io.gryo.GryoIo;
 import org.apache.tinkerpop.gremlin.structure.io.gryo.GryoReader;
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.structure.util.GraphFactory;
 import org.apache.tinkerpop.gremlin.structure.io.gryo.GryoResourceAccess;
 import org.slf4j.Logger;
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/AbstractGremlinTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/AbstractGremlinTest.java
index 2914218..7fd094b 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/AbstractGremlinTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/AbstractGremlinTest.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.process.traversal.Step;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
@@ -51,7 +51,7 @@
 import static org.hamcrest.CoreMatchers.instanceOf;
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeThat;
 
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/GraphManager.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/GraphManager.java
index 7506226..a0eb9f6 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/GraphManager.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/GraphManager.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalEngine;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/GraphProvider.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/GraphProvider.java
index efe270a..da81e15 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/GraphProvider.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/GraphProvider.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
@@ -116,8 +116,7 @@
 
     /**
      * Creates a new {@link Graph} instance using the default
-     * {@code org.apache.commons.configuration.Configuration} from
-     * {@link #standardGraphConfiguration(Class, String, LoadGraphWith.GraphData)}.
+     * {@code Configuration} from {@link #standardGraphConfiguration(Class, String, LoadGraphWith.GraphData)}.
      */
     default public Graph standardTestGraph(final Class<?> test, final String testMethodName, final LoadGraphWith.GraphData loadGraphWith) {
         return GraphFactory.open(standardGraphConfiguration(test, testMethodName, loadGraphWith));
@@ -146,11 +145,11 @@
     /**
      * If possible (usually with persisted graph) clear the space on disk given the configuration that would be used
      * to construct the graph.  The default implementation simply calls
-     * {@link #clear(Graph, org.apache.commons.configuration.Configuration)} with
+     * {@link #clear(Graph, Configuration)} with
      * a null graph argument.
      * <p/>
-     * Implementations should be able to accept an argument of null for the {@code org.apache.commons.configuration.Configuration}
-     * as well, and a proper handling is needed. Otherwise, a NullPointerException may be thrown.
+     * Implementations should be able to accept an argument of null for the {@code Configuration} as well, and a
+     * proper handling is needed. Otherwise, a NullPointerException may be thrown.
      */
     public default void clear(final Configuration configuration) throws Exception {
         clear(null, configuration);
@@ -166,8 +165,8 @@
      * that can be performed is a clear given the configuration.  The method will typically be called this way
      * as clean up task on setup to ensure that a persisted graph has a clear space to create a test graph.
      * <p/>
-     * Implementations should be able to accept an argument of null for the {@code org.apache.commons.configuration.Configuration}
-     * as well, and a proper handling is needed. Otherwise, a NullPointerException may be thrown.
+     * Implementations should be able to accept an argument of null for the {@code Configuration} as well, and a
+     * proper handling is needed. Otherwise, a NullPointerException may be thrown.
      * <p/>
      * Calls to this method may occur multiple times for a specific test. Develop this method to be idempotent.
      */
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/algorithm/generator/CommunityGeneratorTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/algorithm/generator/CommunityGeneratorTest.java
index f8e5cad..2ba5874 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/algorithm/generator/CommunityGeneratorTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/algorithm/generator/CommunityGeneratorTest.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.algorithm.generator;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.AbstractGremlinTest;
 import org.apache.tinkerpop.gremlin.FeatureRequirement;
 import org.apache.tinkerpop.gremlin.FeatureRequirementSet;
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/algorithm/generator/DistributionGeneratorTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/algorithm/generator/DistributionGeneratorTest.java
index 8a2842f..376e8bb 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/algorithm/generator/DistributionGeneratorTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/algorithm/generator/DistributionGeneratorTest.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.algorithm.generator;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.AbstractGremlinTest;
 import org.apache.tinkerpop.gremlin.FeatureRequirement;
 import org.apache.tinkerpop.gremlin.FeatureRequirementSet;
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/FeatureReader.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/FeatureReader.java
new file mode 100644
index 0000000..763cb0e
--- /dev/null
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/FeatureReader.java
@@ -0,0 +1,79 @@
+/*
+ * 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.features;
+
+import org.apache.commons.text.StringEscapeUtils;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Reads the feature files and extracts Gremlin to a {@code Map} structure of the test name as the key with a
+ * {@code List} of Gremlin strings for the value.
+ */
+public class FeatureReader {
+
+    public static Map<String, List<String>> parse(final String projectRoot) throws IOException {
+        final Map<String, List<String>> gremlins = new LinkedHashMap<>();
+        Files.find(Paths.get(projectRoot, "gremlin-test", "features"),
+                   Integer.MAX_VALUE,
+                (filePath, fileAttr) -> fileAttr.isRegularFile() && filePath.toString().endsWith(".feature")).
+                sorted().
+                forEach(f -> {
+                    String currentGremlin = "";
+                    boolean openTriples = false;
+                    boolean skipIgnored = false;
+                    String scenarioName = "";
+
+                    try {
+                        final List<String> lines = Files.readAllLines(f, StandardCharsets.UTF_8);
+                        for (String line : lines) {
+                            String cleanLine = line.trim();
+                            if (cleanLine.startsWith("Scenario:")) {
+                                scenarioName = cleanLine.split(":")[1].trim();
+                                skipIgnored = false;
+                            } else if (cleanLine.startsWith("Then nothing should happen because")) {
+                                skipIgnored = true;
+                            } else if (cleanLine.startsWith("And the graph should return")) {
+                                gremlins.computeIfAbsent(scenarioName, k -> new ArrayList<>()).add(StringEscapeUtils.unescapeJava(cleanLine.substring(cleanLine.indexOf("\"") + 1, cleanLine.lastIndexOf("\""))));
+                            } else if (cleanLine.startsWith("\"\"\"")) {
+                                openTriples = !openTriples;
+                                if (!skipIgnored && !openTriples) {
+                                    gremlins.computeIfAbsent(scenarioName, k -> new ArrayList<>()).add(currentGremlin);
+                                    currentGremlin = "";
+                                }
+                            } else if (openTriples && !skipIgnored) {
+                                currentGremlin += cleanLine;
+                            }
+                        }
+                    } catch (IOException ioe) {
+                        throw new RuntimeException(ioe);
+                    }
+                });
+
+        return gremlins;
+    }
+}
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinEnabledScriptEngineTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinEnabledScriptEngineTest.java
index 7d1e0a7..1ff71d4 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinEnabledScriptEngineTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinEnabledScriptEngineTest.java
@@ -38,7 +38,6 @@
 
 import static org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngineSuite.ENGINE_TO_TEST;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.core.AnyOf.anyOf;
 import static org.hamcrest.core.Is.is;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assume.assumeThat;
@@ -163,12 +162,9 @@
     }
 
     private static GraphTraversal<Vertex, Long> getTraversalWithLambda(final GraphTraversalSource g) {
-        assumeThat("This test is not enabled for this ScriptEngine: " + ENGINE_TO_TEST, ENGINE_TO_TEST,
-                anyOf(is("gremlin-python"), is("gremlin-jython"), is("gremlin-groovy")));
+        assumeThat("This test is not enabled for this ScriptEngine: " + ENGINE_TO_TEST, ENGINE_TO_TEST, is("gremlin-groovy"));
         if (ENGINE_TO_TEST.equals("gremlin-groovy"))
             return g.V().out("created").map(Lambda.function("{x -> x.get().values('name')}")).count();
-        else if (ENGINE_TO_TEST.equals("gremlin-python") || ENGINE_TO_TEST.equals("gremlin-jython"))
-            return g.V().out("created").map(Lambda.function("x : x.get().values('name')")).count();
         else
             throw new RuntimeException("The " + ENGINE_TO_TEST + " ScriptEngine is not supported by this test");
     }
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/AbstractGremlinProcessTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/AbstractGremlinProcessTest.java
index 0a2a405..09044de 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/AbstractGremlinProcessTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/AbstractGremlinProcessTest.java
@@ -20,7 +20,6 @@
 
 import org.apache.tinkerpop.gremlin.AbstractGremlinTest;
 import org.apache.tinkerpop.gremlin.GraphManager;
-import org.apache.tinkerpop.gremlin.process.remote.traversal.RemoteTraversalSideEffects;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalEngine;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalSideEffects;
@@ -35,6 +34,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.UUID;
 import java.util.stream.Collectors;
 
@@ -98,14 +98,7 @@
             assertThat(sideEffects.keys().contains(key), is(true));
             assertThat(sideEffects.exists(key), is(true));
             assertThat(sideEffects.exists(UUID.randomUUID().toString()), is(false));
-
-            // there is slightly different behavior for remote side-effects so carving out a few asserts with that
-            // in mind. the client really doesnt' really have a way of knowing what type of object to create when it
-            // gets an empty iterator so it makes the result null and therefore we end up with a NPE if we try to
-            // access it. the rest of the behavior is solid so better to do this than OptOut I think
-            if (!(sideEffects instanceof RemoteTraversalSideEffects)) {
-                assertEquals(clazz, sideEffects.get((String) keysClasses[i]).getClass());
-            }
+            assertEquals(clazz, sideEffects.get((String) keysClasses[i]).getClass());
         }
         assertEquals(sideEffects.keys().size(), counter);
         assertThat(sideEffects.keys().contains(UUID.randomUUID().toString()), is(false));
@@ -192,10 +185,10 @@
         }
 
         for (int i = 0; i < actualList.size(); i++) {
-            if (!actualList.get(i).getKey().equals(expectedList.get(i).getKey())) {
+            if (!Objects.equals(actualList.get(i).getKey(), expectedList.get(i).getKey())) {
                 return false;
             }
-            if (!actualList.get(i).getValue().equals(expectedList.get(i).getValue())) {
+            if (!Objects.equals(actualList.get(i).getValue(), expectedList.get(i).getValue())) {
                 return false;
             }
         }
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessComputerSuite.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessComputerSuite.java
index 3ca5b76..8785e90 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessComputerSuite.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessComputerSuite.java
@@ -21,10 +21,7 @@
 import org.apache.tinkerpop.gremlin.AbstractGremlinSuite;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputerTest;
-import org.apache.tinkerpop.gremlin.process.computer.bulkdumping.BulkDumperVertexProgramTest;
-import org.apache.tinkerpop.gremlin.process.computer.bulkloading.BulkLoaderVertexProgramTest;
 import org.apache.tinkerpop.gremlin.process.computer.clone.CloneVertexProgramTest;
-import org.apache.tinkerpop.gremlin.process.computer.clustering.peerpressure.PeerPressureVertexProgramTest;
 import org.apache.tinkerpop.gremlin.process.computer.ranking.pagerank.PageRankVertexProgramTest;
 import org.apache.tinkerpop.gremlin.process.computer.search.path.ShortestPathVertexProgramTest;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalEngine;
@@ -92,6 +89,7 @@
 import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.StoreTest;
 import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.SubgraphTest;
 import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.TreeTest;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SeedStrategyProcessTest;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategyProcessTest;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.TranslationStrategyProcessTest;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.EarlyLimitStrategyProcessTest;
@@ -201,10 +199,7 @@
 
             // algorithms
             PageRankVertexProgramTest.class,
-            PeerPressureVertexProgramTest.class,
             ShortestPathVertexProgramTest.class,
-            BulkLoaderVertexProgramTest.class,
-            BulkDumperVertexProgramTest.class,
             CloneVertexProgramTest.class,
 
             // creations
@@ -212,6 +207,7 @@
 
             // decorations
             ReadOnlyStrategyProcessTest.class,
+            SeedStrategyProcessTest.class,
             SubgraphStrategyProcessTest.class,
 
             // optimizations
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessStandardSuite.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessStandardSuite.java
index f127ca0..2f31678 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessStandardSuite.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessStandardSuite.java
@@ -86,6 +86,7 @@
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.ElementIdStrategyProcessTest;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.EventStrategyProcessTest;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.PartitionStrategyProcessTest;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SeedStrategyProcessTest;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategyProcessTest;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.TranslationStrategyProcessTest;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.EarlyLimitStrategyProcessTest;
@@ -193,6 +194,7 @@
             EventStrategyProcessTest.class,
             ReadOnlyStrategyProcessTest.class,
             PartitionStrategyProcessTest.class,
+            SeedStrategyProcessTest.class,
             SubgraphStrategyProcessTest.class,
 
             // optimizations
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/computer/GraphComputerTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/computer/GraphComputerTest.java
index d16c8b8..1cd5de5 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/computer/GraphComputerTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/computer/GraphComputerTest.java
@@ -18,9 +18,9 @@
  */
 package org.apache.tinkerpop.gremlin.process.computer;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.ConfigurationUtils;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.configuration2.ConfigurationUtils;
 import org.apache.tinkerpop.gremlin.ExceptionCoverage;
 import org.apache.tinkerpop.gremlin.LoadGraphWith;
 import org.apache.tinkerpop.gremlin.process.AbstractGremlinProcessTest;
@@ -1168,6 +1168,7 @@
     /////////////////////////////////////////////
 
     /////////////////////////////////////////////
+
     @Test
     @LoadGraphWith(MODERN)
     public void shouldStartAndEndWorkersForVertexProgramAndMapReduce() throws Exception {
@@ -1175,17 +1176,17 @@
         MapReduceI.WORKER_END.clear();
         assertEquals(3, graphProvider.getGraphComputer(graph).program(new VertexProgramJ()).mapReduce(new MapReduceI()).submit().get().memory().<Integer>get("a").intValue());
         if (MapReduceI.WORKER_START.size() == 2) {
-            assertEquals(2, MapReduceI.WORKER_START.size());
+            assertEquals(2, MapReduceI.countTrue(MapReduceI.WORKER_START));
             assertTrue(MapReduceI.WORKER_START.contains(MapReduce.Stage.MAP) && MapReduceI.WORKER_START.contains(MapReduce.Stage.REDUCE));
         } else {
-            assertEquals(3, MapReduceI.WORKER_START.size());
+            assertEquals(3, MapReduceI.countTrue(MapReduceI.WORKER_START));
             assertTrue(MapReduceI.WORKER_START.contains(MapReduce.Stage.MAP) && MapReduceI.WORKER_START.contains(MapReduce.Stage.COMBINE) && MapReduceI.WORKER_START.contains(MapReduce.Stage.REDUCE));
         }
         if (MapReduceI.WORKER_END.size() == 2) {
-            assertEquals(2, MapReduceI.WORKER_END.size());
+            assertEquals(2, MapReduceI.countTrue(MapReduceI.WORKER_END));
             assertTrue(MapReduceI.WORKER_END.contains(MapReduce.Stage.MAP) && MapReduceI.WORKER_END.contains(MapReduce.Stage.REDUCE));
         } else {
-            assertEquals(3, MapReduceI.WORKER_END.size());
+            assertEquals(3, MapReduceI.countTrue(MapReduceI.WORKER_END));
             assertTrue(MapReduceI.WORKER_END.contains(MapReduce.Stage.MAP) && MapReduceI.WORKER_END.contains(MapReduce.Stage.COMBINE) && MapReduceI.WORKER_END.contains(MapReduce.Stage.REDUCE));
         }
     }
@@ -1272,14 +1273,14 @@
         @Override
         public void map(final Vertex vertex, final MapEmitter<NullObject, Integer> emitter) {
             emitter.emit(1);
-            assertEquals(1, WORKER_START.size());
+            assertEquals(1, countTrue(WORKER_START));
             assertTrue(WORKER_START.contains(Stage.MAP));
         }
 
         @Override
         public void combine(final NullObject key, final Iterator<Integer> values, final ReduceEmitter<NullObject, Integer> emitter) {
             emitter.emit(2);
-            assertEquals(2, WORKER_START.size());
+            assertEquals(2, countTrue(WORKER_START));
             assertTrue(WORKER_START.contains(Stage.MAP) && WORKER_START.contains(Stage.COMBINE));
             assertFalse(WORKER_END.isEmpty());
         }
@@ -1287,11 +1288,11 @@
         @Override
         public void reduce(final NullObject key, final Iterator<Integer> values, final ReduceEmitter<NullObject, Integer> emitter) {
             emitter.emit(3);
-            if (WORKER_START.size() == 2) {
-                assertEquals(2, WORKER_START.size());
+            if (IteratorUtils.count(WORKER_START) == 2) {
+                assertEquals(2, countTrue(WORKER_START));
                 assertTrue(WORKER_START.contains(Stage.MAP) && WORKER_START.contains(Stage.REDUCE));
             } else {
-                assertEquals(3, WORKER_START.size());
+                assertEquals(3, countTrue(WORKER_START));
                 assertTrue(WORKER_START.contains(Stage.MAP) && WORKER_START.contains(Stage.COMBINE) && WORKER_START.contains(Stage.REDUCE));
             }
             assertFalse(WORKER_END.isEmpty());
@@ -1315,6 +1316,15 @@
         public String getMemoryKey() {
             return "a";
         }
+
+        /**
+         * Javadoc for {@code ConcurrentSkipListSet} includes this little note: "Beware that, unlike in most
+         * collections, the size method is not a constant-time operation." Doing a traversal of elements will yield
+         * the correct count. Java 11 upgrade seemed to force this failure consistently.
+         */
+        static int countTrue(final Set<Stage> s) {
+            return Long.valueOf(IteratorUtils.count(s)).intValue();
+        }
     }
 
     /////////////////////////////////////////////
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/computer/bulkdumping/BulkDumperVertexProgramTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/computer/bulkdumping/BulkDumperVertexProgramTest.java
deleted file mode 100644
index 62104c0..0000000
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/computer/bulkdumping/BulkDumperVertexProgramTest.java
+++ /dev/null
@@ -1,98 +0,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.
- */
-package org.apache.tinkerpop.gremlin.process.computer.bulkdumping;
-
-import org.apache.tinkerpop.gremlin.LoadGraphWith;
-import org.apache.tinkerpop.gremlin.process.AbstractGremlinProcessTest;
-import org.apache.tinkerpop.gremlin.process.computer.ComputerResult;
-import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
-import org.apache.tinkerpop.gremlin.structure.Direction;
-import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
-import org.junit.Test;
-
-import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.MODERN;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-/**
- * @author Daniel Kuppitz (http://gremlin.guru)
- */
-public class BulkDumperVertexProgramTest extends AbstractGremlinProcessTest {
-
-    @Test
-    @LoadGraphWith(MODERN)
-    public void shouldDumpWholeGraph() throws Exception {
-        if (graphProvider.getGraphComputer(graph).features().supportsResultGraphPersistCombination(GraphComputer.ResultGraph.NEW, GraphComputer.Persist.EDGES)) {
-            final ComputerResult result = graphProvider.getGraphComputer(graph).program(BulkDumperVertexProgram.build().create(graph)).submit().get();
-            result.graph().traversal().V().forEachRemaining(v -> {
-                assertEquals(2, v.keys().size());
-                assertTrue(v.keys().contains("name"));
-                assertTrue(v.keys().contains("age") || v.keys().contains("lang"));
-                assertEquals(1, IteratorUtils.count(v.values("name")));
-                assertEquals(1, IteratorUtils.count(v.values("age", "lang")));
-                final String name = v.value("name");
-                if (name.equals("marko")) {
-                    assertEquals("person", v.label());
-                    assertEquals(Integer.valueOf(29), v.value("age"));
-                    assertEquals(3, IteratorUtils.count(v.edges(Direction.OUT)));
-                    assertEquals(2, IteratorUtils.count(v.edges(Direction.OUT, "knows")));
-                    assertEquals(1, IteratorUtils.count(v.edges(Direction.OUT, "created")));
-                    assertEquals(0, IteratorUtils.count(v.edges(Direction.IN)));
-                } else if (name.equals("vadas")) {
-                    assertEquals("person", v.label());
-                    assertEquals(Integer.valueOf(27), v.value("age"));
-                    assertEquals(0, IteratorUtils.count(v.edges(Direction.OUT)));
-                    assertEquals(1, IteratorUtils.count(v.edges(Direction.IN)));
-                    assertEquals(1, IteratorUtils.count(v.edges(Direction.IN, "knows")));
-                } else if (name.equals("lop")) {
-                    assertEquals("software", v.label());
-                    assertEquals("java", v.value("lang"));
-                    assertEquals(0, IteratorUtils.count(v.edges(Direction.OUT)));
-                    assertEquals(3, IteratorUtils.count(v.edges(Direction.IN)));
-                    assertEquals(3, IteratorUtils.count(v.edges(Direction.IN, "created")));
-                } else if (name.equals("josh")) {
-                    assertEquals("person", v.label());
-                    assertEquals(Integer.valueOf(32), v.value("age"));
-                    assertEquals(2, IteratorUtils.count(v.edges(Direction.OUT)));
-                    assertEquals(2, IteratorUtils.count(v.edges(Direction.OUT, "created")));
-                    assertEquals(1, IteratorUtils.count(v.edges(Direction.IN)));
-                    assertEquals(1, IteratorUtils.count(v.edges(Direction.IN, "knows")));
-                } else if (name.equals("ripple")) {
-                    assertEquals("software", v.label());
-                    assertEquals("java", v.value("lang"));
-                    assertEquals(0, IteratorUtils.count(v.edges(Direction.OUT)));
-                    assertEquals(1, IteratorUtils.count(v.edges(Direction.IN)));
-                    assertEquals(1, IteratorUtils.count(v.edges(Direction.IN, "created")));
-                } else if (name.equals("peter")) {
-                    assertEquals("person", v.label());
-                    assertEquals(Integer.valueOf(35), v.value("age"));
-                    assertEquals(1, IteratorUtils.count(v.edges(Direction.OUT)));
-                    assertEquals(1, IteratorUtils.count(v.edges(Direction.OUT, "created")));
-                    assertEquals(0, IteratorUtils.count(v.edges(Direction.IN)));
-                } else
-                    throw new IllegalStateException("The following vertex should not exist in the graph: " + name);
-            });
-            assertEquals(3.5, (Double) result.graph().traversal().E().values("weight").sum().next(), 0.01);
-            assertEquals(1.5, (Double) result.graph().traversal().E().hasLabel("knows").values("weight").sum().next(), 0.01);
-            assertEquals(2.0, (Double) result.graph().traversal().E().hasLabel("created").values("weight").sum().next(), 0.01);
-            assertEquals(result.memory().getIteration(), 0);
-            assertEquals(result.memory().asMap().size(), 0);
-        }
-    }
-}
\ No newline at end of file
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/computer/bulkloading/BulkLoaderVertexProgramTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/computer/bulkloading/BulkLoaderVertexProgramTest.java
deleted file mode 100644
index 47eb1eb..0000000
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/computer/bulkloading/BulkLoaderVertexProgramTest.java
+++ /dev/null
@@ -1,219 +0,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.
- */
-package org.apache.tinkerpop.gremlin.process.computer.bulkloading;
-
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
-import org.apache.tinkerpop.gremlin.LoadGraphWith;
-import org.apache.tinkerpop.gremlin.TestHelper;
-import org.apache.tinkerpop.gremlin.process.AbstractGremlinProcessTest;
-import org.apache.tinkerpop.gremlin.process.IgnoreEngine;
-import org.apache.tinkerpop.gremlin.process.traversal.TraversalEngine;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
-import org.apache.tinkerpop.gremlin.structure.Direction;
-import org.apache.tinkerpop.gremlin.structure.Element;
-import org.apache.tinkerpop.gremlin.structure.Graph;
-import org.apache.tinkerpop.gremlin.structure.Vertex;
-import org.apache.tinkerpop.gremlin.structure.VertexProperty;
-import org.apache.tinkerpop.gremlin.structure.util.CloseableIterator;
-import org.apache.tinkerpop.gremlin.structure.util.GraphFactory;
-import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
-import org.junit.After;
-import org.junit.Test;
-
-import java.io.File;
-import java.lang.reflect.Field;
-import java.util.Iterator;
-import java.util.function.Function;
-
-import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.MODERN;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-/**
- * @author Daniel Kuppitz (http://gremlin.guru)
- */
-public class BulkLoaderVertexProgramTest extends AbstractGremlinProcessTest {
-
-    final static String TINKERGRAPH_LOCATION = TestHelper.makeTestDataFile(BulkLoaderVertexProgramTest.class, "tinkertest.kryo");
-
-    private BulkLoader getBulkLoader(final BulkLoaderVertexProgram blvp) throws Exception {
-        final Field field = BulkLoaderVertexProgram.class.getDeclaredField("bulkLoader");
-        field.setAccessible(true);
-        return (BulkLoader) field.get(blvp);
-    }
-
-    private Configuration getWriteGraphConfiguration() {
-        final Configuration configuration = new BaseConfiguration();
-        configuration.setProperty(Graph.GRAPH, "org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph");
-        configuration.setProperty("gremlin.tinkergraph.graphLocation", TINKERGRAPH_LOCATION);
-        configuration.setProperty("gremlin.tinkergraph.graphFormat", "gryo");
-        return configuration;
-    }
-
-    private Graph getWriteGraph() {
-        return GraphFactory.open(getWriteGraphConfiguration());
-    }
-
-    @After
-    public void cleanup() {
-        final File graph = new File(TINKERGRAPH_LOCATION);
-        assertTrue(!graph.exists() || graph.delete());
-    }
-
-    @Test
-    public void shouldUseIncrementalBulkLoaderByDefault() throws Exception {
-        final BulkLoader loader = getBulkLoader(BulkLoaderVertexProgram.build().create(graph));
-        assertTrue(loader instanceof IncrementalBulkLoader);
-        assertTrue(loader.keepOriginalIds());
-        assertFalse(loader.useUserSuppliedIds());
-    }
-
-    @Test
-    @LoadGraphWith(MODERN)
-    public void shouldStoreOriginalIds() throws Exception {
-        final BulkLoaderVertexProgram blvp = BulkLoaderVertexProgram.build()
-                .userSuppliedIds(false)
-                .writeGraph(getWriteGraphConfiguration()).create(graph);
-        final BulkLoader loader = getBulkLoader(blvp);
-        assertFalse(loader.useUserSuppliedIds());
-        graphProvider.getGraphComputer(graph).workers(1).program(blvp).submit().get();
-        assertGraphEquality(graph, getWriteGraph(), v -> v.value(loader.getVertexIdProperty()));
-    }
-
-    @Test
-    @LoadGraphWith(MODERN)
-    public void shouldNotStoreOriginalIds() throws Exception {
-        final BulkLoaderVertexProgram blvp = BulkLoaderVertexProgram.build()
-                .userSuppliedIds(true)
-                .writeGraph(getWriteGraphConfiguration()).create(graph);
-        final BulkLoader loader = getBulkLoader(blvp);
-        assertTrue(loader.useUserSuppliedIds());
-        graphProvider.getGraphComputer(graph).workers(1).program(blvp).submit().get();
-        assertGraphEquality(graph, getWriteGraph());
-    }
-
-    @Test
-    @LoadGraphWith(MODERN)
-    public void shouldOverwriteExistingElements() throws Exception {
-        final BulkLoaderVertexProgram blvp = BulkLoaderVertexProgram.build()
-                .userSuppliedIds(true)
-                .writeGraph(getWriteGraphConfiguration()).create(graph);
-        graphProvider.getGraphComputer(graph).workers(1).program(blvp).submit().get(); // initial
-        graphProvider.getGraphComputer(graph).workers(1).program(blvp).submit().get(); // incremental
-        assertGraphEquality(graph, getWriteGraph());
-    }
-
-    @Test
-    @LoadGraphWith(MODERN)
-    @IgnoreEngine(TraversalEngine.Type.COMPUTER) // we can't modify the graph in computer mode
-    public void shouldProperlyHandleMetaProperties() throws Exception {
-        graph.traversal().V().has("name", "marko").properties("name").property("alias", "okram").iterate();
-        final BulkLoaderVertexProgram blvp = BulkLoaderVertexProgram.build()
-                .userSuppliedIds(true)
-                .writeGraph(getWriteGraphConfiguration()).create(graph);
-        graphProvider.getGraphComputer(graph).workers(1).program(blvp).submit().get();
-        assertGraphEquality(graph, getWriteGraph());
-    }
-
-    @Test
-    @LoadGraphWith(MODERN)
-    public void shouldUseOneTimeBulkLoader() throws Exception {
-        for (int iteration = 1; iteration <= 2; iteration++) {
-            final BulkLoaderVertexProgram blvp = BulkLoaderVertexProgram.build()
-                    .bulkLoader(OneTimeBulkLoader.class)
-                    .writeGraph(getWriteGraphConfiguration()).create(graph);
-            final BulkLoader loader = getBulkLoader(blvp);
-            assertTrue(loader instanceof OneTimeBulkLoader);
-            graphProvider.getGraphComputer(graph).workers(1).program(blvp).submit().get();
-            final Graph result = getWriteGraph();
-            assertEquals(6 * iteration, IteratorUtils.count(result.vertices()));
-            assertEquals(6 * iteration, IteratorUtils.count(result.edges()));
-            result.close();
-        }
-    }
-
-    @Test
-    @LoadGraphWith(MODERN)
-    public void shouldUseOneTimeBulkLoaderWithUserSuppliedIds() throws Exception {
-        final BulkLoaderVertexProgram blvp = BulkLoaderVertexProgram.build()
-                .bulkLoader(OneTimeBulkLoader.class)
-                .userSuppliedIds(true)
-                .writeGraph(getWriteGraphConfiguration()).create(graph);
-        final BulkLoader loader = getBulkLoader(blvp);
-        assertTrue(loader instanceof OneTimeBulkLoader);
-        graphProvider.getGraphComputer(graph).workers(1).program(blvp).submit().get();
-        final Graph result = getWriteGraph();
-        assertEquals(6, IteratorUtils.count(result.vertices()));
-        assertEquals(6, IteratorUtils.count(result.edges()));
-        result.close();
-    }
-
-    private static void assertGraphEquality(final Graph source, final Graph target) {
-        assertGraphEquality(source, target, Element::id);
-    }
-
-    private static void assertGraphEquality(final Graph source, final Graph target, final Function<Vertex, Object> idAccessor) {
-        final GraphTraversalSource tg = target.traversal();
-        assertEquals(IteratorUtils.count(source.vertices()), IteratorUtils.count(target.vertices()));
-        assertEquals(IteratorUtils.count(source.edges()), IteratorUtils.count(target.edges()));
-        source.vertices().forEachRemaining(originalVertex -> {
-            Vertex tmpVertex = null;
-            final Iterator<Vertex> vertexIterator = target.vertices();
-            while (vertexIterator.hasNext()) {
-                final Vertex v = vertexIterator.next();
-                if (idAccessor.apply(v).toString().equals(originalVertex.id().toString())) {
-                    tmpVertex = v;
-                    break;
-                }
-            }
-
-            CloseableIterator.closeIterator(vertexIterator);
-
-            assertNotNull(tmpVertex);
-            final Vertex clonedVertex = tmpVertex;
-            assertEquals(IteratorUtils.count(originalVertex.edges(Direction.IN)), IteratorUtils.count(clonedVertex.edges(Direction.IN)));
-            assertEquals(IteratorUtils.count(originalVertex.edges(Direction.OUT)), IteratorUtils.count(clonedVertex.edges(Direction.OUT)));
-            assertEquals(originalVertex.label(), clonedVertex.label());
-            originalVertex.properties().forEachRemaining(originalProperty -> {
-                VertexProperty clonedProperty = null;
-                final Iterator<VertexProperty<Object>> vertexPropertyIterator = clonedVertex.properties(originalProperty.key());
-                while (vertexPropertyIterator.hasNext()) {
-                    final VertexProperty p = vertexPropertyIterator.next();
-                    if (p.value().equals(originalProperty.value())) {
-                        clonedProperty = p;
-                        break;
-                    }
-                }
-                assertNotNull(clonedProperty);
-                assertEquals(originalProperty.isPresent(), clonedProperty.isPresent());
-                assertEquals(originalProperty.value(), clonedProperty.value());
-            });
-            originalVertex.edges(Direction.OUT).forEachRemaining(originalEdge -> {
-                GraphTraversal t = tg.V(clonedVertex).outE(originalEdge.label());
-                originalEdge.properties().forEachRemaining(p -> t.has(p.key(), p.value()));
-                assertTrue(t.hasNext());
-                CloseableIterator.closeIterator(t);
-            });
-        });
-    }
-}
\ No newline at end of file
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/computer/clustering/peerpressure/PeerPressureVertexProgramTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/computer/clustering/peerpressure/PeerPressureVertexProgramTest.java
deleted file mode 100644
index 1d840b0..0000000
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/computer/clustering/peerpressure/PeerPressureVertexProgramTest.java
+++ /dev/null
@@ -1,63 +0,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.
- */
-
-package org.apache.tinkerpop.gremlin.process.computer.clustering.peerpressure;
-
-import org.apache.tinkerpop.gremlin.LoadGraphWith;
-import org.apache.tinkerpop.gremlin.process.AbstractGremlinProcessTest;
-import org.apache.tinkerpop.gremlin.process.computer.ComputerResult;
-import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
-import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
-import org.junit.Test;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.MODERN;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-/**
- * @author Marko A. Rodriguez (http://markorodriguez.com)
- */
-public class PeerPressureVertexProgramTest extends AbstractGremlinProcessTest {
-
-    @Test
-    @LoadGraphWith(MODERN)
-    public void shouldExecutePeerPressure() throws Exception {
-        /*if (g.getGraphComputer().get().features().supportsResultGraphPersistCombination(GraphComputer.ResultGraph.NEW, GraphComputer.Persist.VERTEX_PROPERTIES)) {
-            final ComputerResult result = graph.compute(g.getGraphComputer().get().getClass()).program(PeerPressureVertexProgram.build().create(graph)).submit().get();
-            final Set<Object> clusters = new HashSet<>();
-            result.graph().traversal().V().forEachRemaining(v -> {
-                assertEquals(4, v.keys().size()); // name, age/lang, voteStrength, cluster
-                assertTrue(v.keys().contains("name"));
-                assertTrue(v.keys().contains(PeerPressureVertexProgram.VOTE_STRENGTH));
-                assertTrue(v.keys().contains(PeerPressureVertexProgram.CLUSTER));
-                assertEquals(1, IteratorUtils.count(v.values("name")));
-                assertEquals(1, IteratorUtils.count(v.values(PeerPressureVertexProgram.CLUSTER)));
-                final Object cluster = v.value(PeerPressureVertexProgram.CLUSTER);
-                clusters.add(cluster);
-            });
-            //assertEquals(2, clusters.size());
-            //assertEquals(3, result.memory().getIteration());
-            assertEquals(1, result.memory().asMap().size());
-            assertTrue(result.memory().keys().contains("gremlin.peerPressureVertexProgram.voteToHalt"));  // this is private in PeerPressureVertexProgram (and that is okay)
-        }*/
-    }
-}
\ No newline at end of file
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/computer/search/path/ShortestPathTestHelper.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/computer/search/path/ShortestPathTestHelper.java
index 7f3aa63..6fde250 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/computer/search/path/ShortestPathTestHelper.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/computer/search/path/ShortestPathTestHelper.java
@@ -38,7 +38,7 @@
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.is;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 
 /**
  * @author Daniel Kuppitz (http://gremlin.guru)
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/CoreTraversalTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/CoreTraversalTest.java
index cf34ee2..7fbc8b5 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/CoreTraversalTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/CoreTraversalTest.java
@@ -51,7 +51,8 @@
 import static org.hamcrest.core.StringStartsWith.startsWith;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertNull;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -68,6 +69,44 @@
 public class CoreTraversalTest extends AbstractGremlinProcessTest {
 
     @Test
+    @LoadGraphWith(MODERN)
+    @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_ADD_VERTICES)
+    @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_ADD_PROPERTY)
+    @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_NULL_PROPERTY_VALUES)
+    public void g_addVXpersonX_propertyXname_nullX() {
+        final Traversal<Vertex, Vertex> traversal = g.addV("person").property("name", null);
+        printTraversalForm(traversal);
+        final Vertex nulled = traversal.next();
+        assertFalse(traversal.hasNext());
+        assertEquals("person", nulled.label());
+        assertNull(nulled.value("name"));
+        assertEquals(1, IteratorUtils.count(nulled.properties()));
+        assertEquals(7, IteratorUtils.count(g.V()));
+    }
+
+    @Test
+    @LoadGraphWith(MODERN)
+    @FeatureRequirement(featureClass = Graph.Features.EdgeFeatures.class, feature = Graph.Features.EdgeFeatures.FEATURE_ADD_EDGES)
+    @FeatureRequirement(featureClass = Graph.Features.EdgeFeatures.class, feature = Graph.Features.EdgeFeatures.FEATURE_NULL_PROPERTY_VALUES)
+    public void g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX_propertyXweight_nullX() {
+        final Traversal<Vertex, Edge> traversal = g.V(convertToVertexId("marko")).as("a").out("created").addE("createdBy").to("a").property("weight", null);
+        printTraversalForm(traversal);
+        int count = 0;
+        while (traversal.hasNext()) {
+            final Edge edge = traversal.next();
+            assertEquals("createdBy", edge.label());
+            assertNull(g.E(edge).<Double>values("weight").next());
+            assertEquals(1, g.E(edge).properties().count().next().intValue());
+            count++;
+
+
+        }
+        assertEquals(1, count);
+        assertEquals(7, IteratorUtils.count(g.E()));
+        assertEquals(6, IteratorUtils.count(g.V()));
+    }
+
+    @Test
     @LoadGraphWith
     public void shouldNeverPropagateANoBulkTraverser() {
         try {
@@ -80,18 +119,6 @@
     }
 
     @Test
-    @LoadGraphWith
-    public void shouldNeverPropagateANullValuedTraverser() {
-        try {
-            assertFalse(g.V().map(t -> null).hasNext());
-            assertEquals(0, g.V().map(t -> null).toList().size());
-            g.V().map(t -> null).sideEffect(t -> fail("this should not have happened")).iterate();
-        } catch (VerificationException e) {
-            // its okay if lambdas can't be serialized by the test suite
-        }
-    }
-
-    @Test
     @LoadGraphWith(MODERN)
     public void shouldFilterOnIterate() {
         final Traversal<Vertex,String> traversal = g.V().out().out().<String>values("name").aggregate("x").iterate();
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalInterruptionComputerTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalInterruptionComputerTest.java
index 7545f18..2021a56 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalInterruptionComputerTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalInterruptionComputerTest.java
@@ -36,7 +36,7 @@
 import java.util.function.UnaryOperator;
 
 import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.GRATEFUL;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 
 /**
  * @author Stephen Mallette (http://stephen.genoprime.com)
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalInterruptionTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalInterruptionTest.java
index 6588a6b..8e390ea 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalInterruptionTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalInterruptionTest.java
@@ -38,7 +38,7 @@
 import java.util.function.UnaryOperator;
 
 import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.GRATEFUL;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 
 /**
  * @author Stephen Mallette (http://stephen.genoprime.com)
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/ComplexTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/ComplexTest.java
index 0110d44..f7735c6 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/ComplexTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/ComplexTest.java
@@ -317,27 +317,27 @@
             return g.withoutStrategies(ComputerVerificationStrategy.class, PathRetractionStrategy.class).
                     V().as("v").both().as("v").
                     project("src", "tgt", "p").
-                    by(select(first, "v")).
-                    by(select(last, "v")).
-                    by(select(all, "v")).as("triple").
+                      by(select(first, "v")).
+                      by(select(last, "v")).
+                      by(select(all, "v")).as("triple").
                     group("x").
-                    by(select("src", "tgt")).
-                    by(select("p").fold()).select("tgt").barrier().
+                      by(select("src", "tgt")).
+                      by(select("p").fold()).select("tgt").barrier().
                     repeat(both().as("v").
                             project("src", "tgt", "p").
-                            by(select(first, "v")).
-                            by(select(last, "v")).
-                            by(select(all, "v")).as("t").
+                              by(select(first, "v")).
+                              by(select(last, "v")).
+                              by(select(all, "v")).as("t").
                             filter(select(all, "p").count(local).as("l").
-                                    select(last, "t").select(all, "p").dedup(local).count(local).where(eq("l"))).
+                                   select(last, "t").select(all, "p").dedup(local).count(local).where(eq("l"))).
                             select(last, "t").
                             not(select(all, "p").as("p").count(local).as("l").
-                                    select(all, "x").unfold().filter(select(keys).where(eq("t")).by(select("src", "tgt"))).
-                                    filter(select(values).unfold().or(count(local).where(lt("l")), where(eq("p"))))).
+                                select(all, "x").unfold().filter(select(keys).where(eq("t")).by(select("src", "tgt"))).
+                                filter(select(values).unfold().or(count(local).where(lt("l")), where(eq("p"))))).
                             barrier().
                             group("x").
-                            by(select("src", "tgt")).
-                            by(select(all, "p").fold()).select("tgt").barrier()).
+                              by(select("src", "tgt")).
+                              by(select(all, "p").fold()).select("tgt").barrier()).
                     cap("x").select(values).unfold().unfold().map(unfold().id().fold());
         }
 
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/DedupTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/DedupTest.java
index 850c99f..c36d10d 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/DedupTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/DedupTest.java
@@ -43,6 +43,7 @@
 import java.util.Map;
 import java.util.Set;
 
+import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.CREW;
 import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.MODERN;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.both;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.bothE;
@@ -96,6 +97,12 @@
 
     public abstract Traversal<Vertex, String> get_g_V_both_group_by_byXout_dedup_foldX_unfold_selectXvaluesX_unfold_out_order_byXnameX_limitX1X_valuesXnameX();
 
+    public abstract Traversal<Vertex, Long> get_g_V_bothE_properties_dedup_count();
+
+    public abstract Traversal<Vertex, Long> get_g_V_both_properties_dedup_count();
+
+    public abstract Traversal<Vertex, Long> get_g_V_both_properties_properties_dedup_count();
+
     @Test
     @LoadGraphWith(MODERN)
     public void g_V_out_in_valuesXnameX_fold_dedupXlocalX_unfold() {
@@ -332,6 +339,33 @@
         assertFalse(traversal.hasNext());
     }
 
+    @Test
+    @LoadGraphWith(MODERN)
+    public void g_V_bothE_properties_dedup_count() {
+        final Traversal<Vertex, Long> traversal = get_g_V_bothE_properties_dedup_count();
+        printTraversalForm(traversal);
+        assertEquals(4L, traversal.next().longValue());
+        assertFalse(traversal.hasNext());
+    }
+
+    @Test
+    @LoadGraphWith(MODERN)
+    public void g_V_both_properties_dedup_count() {
+        // vertex properties behave like Element with their dedup() so 12 is the right number there
+        final Traversal<Vertex, Long> traversal = get_g_V_both_properties_dedup_count();
+        printTraversalForm(traversal);
+        assertEquals(12L, traversal.next().longValue());
+        assertFalse(traversal.hasNext());
+    }
+
+    @Test
+    @LoadGraphWith(CREW)
+    public void g_V_both_properties_properties_dedup_count() {
+        final Traversal<Vertex, Long> traversal = get_g_V_both_properties_properties_dedup_count();
+        printTraversalForm(traversal);
+        assertEquals(21L, traversal.next().longValue());
+        assertFalse(traversal.hasNext());
+    }
 
     public static class Traversals extends DedupTest {
         @Override
@@ -423,5 +457,20 @@
                     unfold().
                     out().order().by("name").limit(1).values("name");
         }
+
+        @Override
+        public Traversal<Vertex, Long> get_g_V_bothE_properties_dedup_count() {
+            return g.V().bothE().properties().dedup().count();
+        }
+
+        @Override
+        public Traversal<Vertex, Long> get_g_V_both_properties_dedup_count() {
+            return g.V().both().properties().dedup().count();
+        }
+
+        @Override
+        public Traversal<Vertex, Long> get_g_V_both_properties_properties_dedup_count() {
+            return g.V().both().properties().properties().dedup().count();
+        }
     }
 }
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/HasTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/HasTest.java
index 94c831a..1e59ffa 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/HasTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/HasTest.java
@@ -45,7 +45,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertTrue;
 
 /**
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/RangeTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/RangeTest.java
index 3a565be..5480108 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/RangeTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/RangeTest.java
@@ -183,7 +183,7 @@
     }
 
     /**
-     * Scenario: limit step, Scope.local, >1 item requested, List<String> input, List<String> output
+     * Scenario: limit step, Scope.local, &gt;1 item requested, List&lt;String&gt; input, List&lt;String&gt; output
      */
     @Test
     @LoadGraphWith(MODERN)
@@ -212,7 +212,7 @@
     }
 
     /**
-     * Scenario: range step, Scope.local, >1 item requested, List<String> input, List<String> output
+     * Scenario: range step, Scope.local, &gt;1 item requested, List&lt;String&gt; input, List&lt;String&gt; output
      */
     @Test
     @LoadGraphWith(MODERN)
@@ -256,7 +256,7 @@
     }
 
     /**
-     * Scenario: limit step, Scope.local, >1 item requested, Map input, Map output
+     * Scenario: limit step, Scope.local, &gt;1 item requested, Map input, Map output
      */
     @Test
     @LoadGraphWith(MODERN)
@@ -286,7 +286,7 @@
     }
 
     /**
-     * Scenario: range step, Scope.local, >1 item requested, Map input, Map output
+     * Scenario: range step, Scope.local, &gt;1 item requested, Map input, Map output
      */
     @Test
     @LoadGraphWith(MODERN)
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/TailTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/TailTest.java
index f48d0af..ce02bb3 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/TailTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/TailTest.java
@@ -147,7 +147,7 @@
     }
 
     /**
-     * Scenario: Local scope, List input, N>1
+     * Scenario: Local scope, List input, N&gt;1
      */
     @Test
     @LoadGraphWith(MODERN)
@@ -202,7 +202,7 @@
     }
 
     /**
-     * Scenario: Local scope, Map input, N>1
+     * Scenario: Local scope, Map input, N&gt;1
      */
     @Test
     @LoadGraphWith(MODERN)
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeTest.java
index 54c4091..1e7f162 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeTest.java
@@ -44,6 +44,8 @@
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.select;
 import static org.apache.tinkerpop.gremlin.structure.Column.keys;
 import static org.apache.tinkerpop.gremlin.structure.Column.values;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.Is.is;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 
@@ -58,6 +60,8 @@
 
     public abstract Traversal<Vertex, Edge> get_g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX_propertyXweight_2X(final Object v1Id);
 
+    public abstract Traversal<Vertex, Edge> get_g_V_outE_propertyXweight_nullX();
+
     public abstract Traversal<Vertex, Edge> get_g_V_aggregateXxX_asXaX_selectXxX_unfold_addEXexistsWithX_toXaX_propertyXtime_nowX();
 
     public abstract Traversal<Vertex, Edge> get_g_V_asXaX_outXcreatedX_inXcreatedX_whereXneqXaXX_asXbX_addEXcodeveloperX_fromXaX_toXbX_propertyXyear_2009X();
@@ -120,6 +124,15 @@
 
     @Test
     @LoadGraphWith(MODERN)
+    @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_NULL_PROPERTY_VALUES, supported = false)
+    public void g_V_outE_propertyXweight_nullX() {
+        final Traversal<Vertex, Edge> traversal = get_g_V_outE_propertyXweight_nullX();
+        printTraversalForm(traversal);
+        traversal.forEachRemaining(e -> assertThat(e.properties("weight").hasNext(), is(false)));
+    }
+
+    @Test
+    @LoadGraphWith(MODERN)
     @FeatureRequirement(featureClass = Graph.Features.EdgeFeatures.class, feature = Graph.Features.EdgeFeatures.FEATURE_ADD_EDGES)
     public void g_V_aggregateXxX_asXaX_selectXxX_unfold_addEXexistsWithX_toXaX_propertyXtime_nowX() {
         final Traversal<Vertex, Edge> traversal = get_g_V_aggregateXxX_asXaX_selectXxX_unfold_addEXexistsWithX_toXaX_propertyXtime_nowX();
@@ -306,6 +319,11 @@
         }
 
         @Override
+        public Traversal<Vertex, Edge> get_g_V_outE_propertyXweight_nullX() {
+            return g.V().outE().property("weight", null);
+        }
+
+        @Override
         public Traversal<Vertex, Edge> get_g_V_aggregateXxX_asXaX_selectXxX_unfold_addEXexistsWithX_toXaX_propertyXtime_nowX() {
             return g.V().aggregate("x").as("a").select("x").unfold().addE("existsWith").to("a").property("time", "now");
         }
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexTest.java
index 21fbb8c..ad0e1dd 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexTest.java
@@ -40,8 +40,11 @@
 import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.MODERN;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.V;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.select;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.Is.is;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 /**
@@ -56,6 +59,12 @@
 
     public abstract Traversal<Vertex, Vertex> get_g_addVXpersonX_propertyXname_stephenX();
 
+    public abstract Traversal<Vertex, Vertex> get_g_V_hasLabelXpersonX_propertyXname_nullX();
+
+    public abstract Traversal<Vertex, Vertex> get_g_addVXnullX_propertyXid_nullX();
+
+    public abstract Traversal<Vertex, Vertex> get_g_addV_propertyXlabel_personX();
+
     public abstract Traversal<Vertex, Vertex> get_g_addVXpersonX_propertyXsingle_name_stephenX_propertyXsingle_name_stephenmX();
 
     public abstract Traversal<Vertex, Vertex> get_g_addVXpersonX_propertyXsingle_name_stephenX_propertyXsingle_name_stephenm_since_2010X();
@@ -91,7 +100,6 @@
         assertEquals(7, IteratorUtils.count(g.V()));
     }
 
-
     @Test
     @LoadGraphWith(MODERN)
     @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_ADD_VERTICES)
@@ -112,6 +120,31 @@
     }
 
     @Test
+    @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_ADD_VERTICES)
+    @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_ADD_PROPERTY)
+    public void g_addVXnullX_propertyXid_nullX() {
+        final Traversal<Vertex, Vertex> traversal = get_g_addVXnullX_propertyXid_nullX();
+        printTraversalForm(traversal);
+
+        final Vertex vertex = traversal.next();
+        assertEquals(Vertex.DEFAULT_LABEL, vertex.label());
+
+        // should generate an id for the null value
+        assertNotNull(vertex.id());
+    }
+
+    @Test
+    @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_ADD_VERTICES)
+    @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_ADD_PROPERTY)
+    public void g_addV_propertyXlabel_personX() {
+        final Traversal<Vertex, Vertex> traversal = get_g_addV_propertyXlabel_personX();
+        printTraversalForm(traversal);
+
+        final Vertex vertex = traversal.next();
+        assertEquals("person", vertex.label());
+    }
+
+    @Test
     @LoadGraphWith(MODERN)
     @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_ADD_VERTICES)
     @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_ADD_PROPERTY)
@@ -128,6 +161,15 @@
 
     @Test
     @LoadGraphWith(MODERN)
+    @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_NULL_PROPERTY_VALUES, supported = false)
+    public void g_V_hasLabelXpersonX_propertyXname_nullX() {
+        final Traversal<Vertex, Vertex> traversal = get_g_V_hasLabelXpersonX_propertyXname_nullX();
+        printTraversalForm(traversal);
+        traversal.forEachRemaining(v -> assertThat(v.properties("name").hasNext(), is(false)));
+    }
+
+    @Test
+    @LoadGraphWith(MODERN)
     @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_ADD_VERTICES)
     @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_ADD_PROPERTY)
     public void g_addVXpersonX_propertyXsingle_name_stephenX_propertyXsingle_name_stephenmX() {
@@ -315,6 +357,11 @@
         }
 
         @Override
+        public Traversal<Vertex, Vertex> get_g_V_hasLabelXpersonX_propertyXname_nullX() {
+            return g.V().hasLabel("person").property("name", null);
+        }
+
+        @Override
         public Traversal<Vertex, Vertex> get_g_addVXpersonX_propertyXsingle_name_stephenX_propertyXsingle_name_stephenmX() {
             return g.addV("person").property(VertexProperty.Cardinality.single, "name", "stephen").property(VertexProperty.Cardinality.single, "name", "stephenm");
         }
@@ -363,5 +410,16 @@
         public Traversal<Vertex, Map<Object, Object>> get_g_V_asXaX_hasXname_markoX_outXcreatedX_asXbX_addVXselectXaX_labelX_propertyXtest_selectXbX_labelX_valueMap_withXtokensX() {
             return g.V().as("a").has("name", "marko").out("created").as("b").addV(select("a").label()).property("test", select("b").label()).valueMap().with(WithOptions.tokens);
         }
+
+        @Override
+        public Traversal<Vertex, Vertex> get_g_addVXnullX_propertyXid_nullX() {
+            // testing Traversal but should work the same for String
+            return g.addV((Traversal.Admin<?, String>) null).property(T.id, null);
+        }
+
+        @Override
+        public Traversal<Vertex, Vertex> get_g_addV_propertyXlabel_personX() {
+            return g.addV().property(T.label, "person");
+        }
     }
 }
\ No newline at end of file
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConstantTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConstantTest.java
index e35db43..07a7b55 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConstantTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConstantTest.java
@@ -46,9 +46,10 @@
 
     public abstract Traversal<Vertex, Integer> get_g_V_constantX123X();
 
+    public abstract Traversal<Vertex, Void> get_g_V_constantXnullX();
+
     public abstract Traversal<Vertex, String> get_g_V_chooseXhasLabelXpersonX_valuesXnameX_constantXinhumanXX();
 
-    /** Scenario: Trivial use case from GraphTraversal */
     @Test
     @LoadGraphWith(MODERN)
     public void g_V_constantX123X() {
@@ -56,6 +57,13 @@
         printTraversalForm(traversal);
         assertEquals(Arrays.asList(123, 123, 123, 123, 123, 123), traversal.toList());
     }
+    @Test
+    @LoadGraphWith(MODERN)
+    public void g_V_constantXnullX() {
+        final Traversal<Vertex, Void> traversal = get_g_V_constantXnullX();
+        printTraversalForm(traversal);
+        assertEquals(Arrays.asList(null, null, null, null, null, null), traversal.toList());
+    }
 
     /** Scenario: Anonymous traversal within choose */
     @Test
@@ -74,6 +82,11 @@
         }
 
         @Override
+        public Traversal<Vertex, Void> get_g_V_constantXnullX() {
+            return g.V().constant(null);
+        }
+
+        @Override
         public Traversal<Vertex, String> get_g_V_chooseXhasLabelXpersonX_valuesXnameX_constantXinhumanXX() {
             return g.V().choose(hasLabel("person"), values("name"), constant("inhuman"));
         }
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapTest.java
index 9006fec..35faa03 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapTest.java
@@ -31,9 +31,11 @@
 import java.util.List;
 
 import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.MODERN;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.constant;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.select;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 /**
@@ -53,6 +55,8 @@
 
     public abstract Traversal<Vertex, Vertex> get_g_V_mapXselectXaXX();
 
+    public abstract Traversal<Vertex, Vertex> get_g_V_mapXconstantXnullXX();
+
     @Test
     @LoadGraphWith(MODERN)
     public void g_VX1X_mapXnameX() {
@@ -139,6 +143,19 @@
         assertEquals(6, counter);
     }
 
+    @Test
+    @LoadGraphWith(MODERN)
+    public void g_V_mapXconstantXnullXX() {
+        final Traversal<Vertex, Vertex> traversal = get_g_V_mapXconstantXnullXX();
+        printTraversalForm(traversal);
+        int counter = 0;
+        while (traversal.hasNext()) {
+            counter++;
+            assertNull(traversal.next());
+        }
+        assertEquals(6, counter);
+    }
+
     public static class Traversals extends MapTest {
         @Override
         public Traversal<Vertex, String> get_g_VX1X_mapXnameX(final Object v1Id) {
@@ -169,5 +186,10 @@
         public Traversal<Vertex, Vertex> get_g_V_mapXselectXaXX() {
             return g.V().as("a").map(select("a"));
         }
+
+        @Override
+        public Traversal<Vertex, Vertex> get_g_V_mapXconstantXnullXX() {
+            return g.V().map(constant(null));
+        }
     }
 }
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchTest.java
index 965def1..a5a7595 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchTest.java
@@ -69,6 +69,8 @@
 
     public abstract Traversal<Vertex, Map<String, Object>> get_g_V_valueMap_matchXa_selectXnameX_bX();
 
+    public abstract Traversal<Vertex, Map<String, Object>> get_g_V_matchXa_outXknowsX_name_bX_identity();
+
     // very basic query
     public abstract Traversal<Vertex, Map<String, Vertex>> get_g_V_matchXa_out_bX();
 
@@ -608,6 +610,16 @@
                 "a", "josh", "b", "ripple"), traversal);
     }
 
+    @Test
+    @LoadGraphWith(MODERN)
+    public void g_V_matchXa_outXknowsX_name_bX_identity() {
+        final Traversal<Vertex, Map<String, Object>> traversal = get_g_V_matchXa_outXknowsX_name_bX_identity();
+        printTraversalForm(traversal);
+        checkResults(makeMapList(2,
+                "a", convertToVertex(graph, "marko"), "b", "vadas",
+                "a", convertToVertex(graph, "marko"), "b", "josh"), traversal);
+    }
+
     public static class GreedyMatchTraversals extends Traversals {
         @Before
         public void setupTest() {
@@ -627,6 +639,11 @@
         }
 
         @Override
+        public Traversal<Vertex, Map<String, Object>> get_g_V_matchXa_outXknowsX_name_bX_identity() {
+            return g.V().match(__.as("a").out("knows").values("name").as("b")).identity();
+        }
+
+        @Override
         public Traversal<Vertex, Map<String, Vertex>> get_g_V_matchXa_out_bX() {
             return g.V().match(as("a").out().as("b"));
         }
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderTest.java
index edca31d..efcbea9 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderTest.java
@@ -29,6 +29,7 @@
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
 import org.apache.tinkerpop.gremlin.structure.Column;
+import org.apache.tinkerpop.gremlin.structure.Property;
 import org.apache.tinkerpop.gremlin.structure.T;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.junit.Test;
@@ -48,7 +49,7 @@
 import static org.hamcrest.core.Is.is;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -64,14 +65,10 @@
 
     public abstract Traversal<Vertex, String> get_g_V_name_order_byXa1_b1X_byXb2_a2X();
 
-    public abstract Traversal<Vertex, String> get_g_V_order_byXname_incrX_name();
-
     public abstract Traversal<Vertex, String> get_g_V_order_byXname_ascX_name();
 
     public abstract Traversal<Vertex, String> get_g_V_order_byXnameX_name();
 
-    public abstract Traversal<Vertex, Double> get_g_V_outE_order_byXweight_decrX_weight();
-
     public abstract Traversal<Vertex, Double> get_g_V_outE_order_byXweight_descX_weight();
 
     public abstract Traversal<Vertex, String> get_g_V_order_byXname_a1_b1X_byXname_b2_a2X_name();
@@ -110,6 +107,10 @@
 
     public abstract Traversal<Vertex, Map.Entry<Object, Object>> get_g_VX1X_elementMap_orderXlocalX_byXkeys_descXunfold(final Object v1Id);
 
+    public abstract Traversal<Vertex, Vertex> get_g_V_order_byXlabelX();
+
+    public abstract Traversal<Vertex, Vertex> get_g_V_order_byXlabel_descX();
+
     @Test
     @LoadGraphWith(MODERN)
     public void g_V_name_order() {
@@ -128,14 +129,6 @@
 
     @Test
     @LoadGraphWith(MODERN)
-    public void g_V_order_byXname_incrX_name() {
-        final Traversal<Vertex, String> traversal = get_g_V_order_byXname_incrX_name();
-        printTraversalForm(traversal);
-        checkOrderedResults(Arrays.asList("josh", "lop", "marko", "peter", "ripple", "vadas"), traversal);
-    }
-
-    @Test
-    @LoadGraphWith(MODERN)
     public void g_V_order_byXname_ascX_name() {
         final Traversal<Vertex, String> traversal = get_g_V_order_byXname_ascX_name();
         printTraversalForm(traversal);
@@ -152,14 +145,6 @@
 
     @Test
     @LoadGraphWith(MODERN)
-    public void g_V_outE_order_byXweight_decrX_weight() {
-        final Traversal<Vertex, Double> traversal = get_g_V_outE_order_byXweight_decrX_weight();
-        printTraversalForm(traversal);
-        checkOrderedResults(Arrays.asList(1.0d, 1.0d, 0.5d, 0.4d, 0.4d, 0.2d), traversal);
-    }
-
-    @Test
-    @LoadGraphWith(MODERN)
     public void g_V_outE_order_byXweight_descX_weight() {
         final Traversal<Vertex, Double> traversal = get_g_V_outE_order_byXweight_descX_weight();
         printTraversalForm(traversal);
@@ -425,6 +410,22 @@
         assertEquals(1.9, entry.getValue().doubleValue(), 0.0001);
     }
 
+    public void g_V_order_byXlabelX() {
+        final Traversal<Vertex, Vertex> traversal = get_g_V_order_byXlabelX();
+        printTraversalForm(traversal);
+        for (int i = 0; i < 4; i++) {
+            assertTrue(traversal.hasNext());
+            final Vertex v = traversal.next();
+            assertEquals("person", v.label());
+        }
+        for (int i = 0; i < 2; i++) {
+            assertTrue(traversal.hasNext());
+            final Vertex v = traversal.next();
+            assertEquals("software", v.label());
+        }
+        assertFalse(traversal.hasNext());
+    }
+
     @Test
     @LoadGraphWith(MODERN)
     public void g_V_hasLabelXpersonX_group_byXnameX_byXoutE_weight_sumX_unfold_order_byXvalues_descX() {
@@ -448,6 +449,22 @@
         assertFalse(traversal.hasNext());
     }
 
+    public void g_V_order_byXlabel_descX() {
+        final Traversal<Vertex, Vertex> traversal = get_g_V_order_byXlabel_descX();
+        printTraversalForm(traversal);
+        for (int i = 0; i < 2; i++) {
+            assertTrue(traversal.hasNext());
+            final Vertex v = traversal.next();
+            assertEquals("software", v.label());
+        }
+        for (int i = 0; i < 4; i++) {
+            assertTrue(traversal.hasNext());
+            final Vertex v = traversal.next();
+            assertEquals("person", v.label());
+        }
+        assertFalse(traversal.hasNext());
+    }
+
     @Test
     @LoadGraphWith(MODERN)
     public void g_VX1X_elementMap_orderXlocalX_byXkeys_descXunfold() {
@@ -489,11 +506,6 @@
         }
 
         @Override
-        public Traversal<Vertex, String> get_g_V_order_byXname_incrX_name() {
-            return g.V().order().by("name", Order.incr).values("name");
-        }
-
-        @Override
         public Traversal<Vertex, String> get_g_V_order_byXname_ascX_name() {
             return g.V().order().by("name", Order.asc).values("name");
         }
@@ -504,11 +516,6 @@
         }
 
         @Override
-        public Traversal<Vertex, Double> get_g_V_outE_order_byXweight_decrX_weight() {
-            return g.V().outE().order().by("weight", Order.decr).values("weight");
-        }
-
-        @Override
         public Traversal<Vertex, Double> get_g_V_outE_order_byXweight_descX_weight() {
             return g.V().outE().order().by("weight", desc).values("weight");
         }
@@ -611,5 +618,14 @@
         public Traversal<Vertex, Map.Entry<Object, Object>> get_g_VX1X_elementMap_orderXlocalX_byXkeys_descXunfold(final Object v1Id) {
             return g.V(v1Id).elementMap().order(Scope.local).by(keys, desc).unfold();
         }
+
+        public Traversal<Vertex, Vertex> get_g_V_order_byXlabelX() {
+            return g.V().order().by(__.label());
+        }
+
+        @Override
+        public Traversal<Vertex, Vertex> get_g_V_order_byXlabel_descX() {
+            return g.V().order().by(__.label(), Order.desc);
+        }
     }
 }
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PageRankTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PageRankTest.java
index 864ebb0..33ba805 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PageRankTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PageRankTest.java
@@ -51,24 +51,22 @@
 
     public abstract Traversal<Vertex, Vertex> get_g_V_pageRank_hasXpageRankX();
 
-    public abstract Traversal<Vertex, Map<Object, List<Object>>> get_g_V_outXcreatedX_pageRank_byXbothEX_byXprojectRankX_timesX0X_valueMapXname_projectRankX();
+    public abstract Traversal<Vertex, Map<Object, List<Object>>> get_g_V_outXcreatedX_pageRank_withXedges_bothEX_withXpropertyName_projectRankXwithXtimes_0X_valueMapXname_projectRankX();
 
     public abstract Traversal<Vertex, String> get_g_V_pageRank_order_byXpageRank_descX_byXnameX_name();
 
     public abstract Traversal<Vertex, String> get_g_V_pageRank_order_byXpageRank_descX_name_limitX2X();
 
-    public abstract Traversal<Vertex, Map<String, Object>> get_g_V_pageRank_byXoutEXknowsXX_byXfriendRankX_project_byXnameX_byXvaluesXfriendRankX_mathX();
+    public abstract Traversal<Vertex, Map<String, Object>> get_g_V_pageRank_withXedges_outEXknowsXX_withXpropertyName_friendRankX_project_byXnameX_byXvaluesXfriendRankX_mathX();
 
-    public abstract Traversal<Vertex, Map<String, Object>> get_g_V_hasLabelXpersonX_pageRank_byXpageRankX_project_byXnameX_byXvaluesXpageRankX_mathX();
+    public abstract Traversal<Vertex, Map<String, Object>> get_g_V_hasLabelXpersonX_pageRank_withXpropertyName_pageRankX_project_byXnameX_byXvaluesXpageRankX_mathX();
 
-    public abstract Traversal<Vertex, Map<String, Object>> get_g_V_pageRank_byXpageRankX_asXaX_outXknowsX_pageRank_asXbX_selectXa_bX_by_byXmathX();
+    public abstract Traversal<Vertex, Map<String, Object>> get_g_V_pageRank_withXpropertyName_pageRankX_asXaX_outXknowsX_pageRank_asXbX_selectXa_bX_by_byXmathX();
 
-    public abstract Traversal<Vertex, Map<Object, List<Object>>> get_g_V_hasLabelXsoftwareX_hasXname_rippleX_pageRankX1X_byXinEXcreatedXX_timesX1X_byXpriorsX_inXcreatedX_unionXboth__identityX_valueMapXname_priorsX();
+    public abstract Traversal<Vertex, Map<Object, List<Object>>> get_g_V_hasLabelXsoftwareX_hasXname_rippleX_pageRankX1X_withXedges_inEXcreatedXX_withXtimes_1X_withXpropertyName_priorsX_inXcreatedX_unionXboth__identityX_valueMapXname_priorsX();
 
     public abstract Traversal<Vertex, Map<Object, List<Vertex>>> get_g_V_outXcreatedX_groupXmX_byXlabelX_pageRankX1X_withXpropertyName_pageRankXX_withXedges_inEXX_withXtimes_1X_inXcreatedX_groupXmX_byXpageRankX_capXmX();
 
-    public abstract Traversal<Vertex, Map<Object, List<Vertex>>> get_g_V_outXcreatedX_groupXmX_byXlabelX_pageRankX1X_byXpageRankX_byXinEX_timesX1X_inXcreatedX_groupXmX_byXpageRankX_capXmX();
-
     @Test
     @LoadGraphWith(MODERN)
     public void g_V_pageRank_hasXpageRankX() {
@@ -79,8 +77,8 @@
 
     @Test
     @LoadGraphWith(MODERN)
-    public void g_V_outXcreatedX_pageRank_byXbothEX_byXprojectRankX_valueMapXname_projectRankX() {
-        final Traversal<Vertex, Map<Object, List<Object>>> traversal = get_g_V_outXcreatedX_pageRank_byXbothEX_byXprojectRankX_timesX0X_valueMapXname_projectRankX();
+    public void g_V_outXcreatedX_pageRank_withXedges_bothEX_withXpropertyName_projectRankXwithXtimes_0X_valueMapXname_projectRankX() {
+        final Traversal<Vertex, Map<Object, List<Object>>> traversal = get_g_V_outXcreatedX_pageRank_withXedges_bothEX_withXpropertyName_projectRankXwithXtimes_0X_valueMapXname_projectRankX();
         printTraversalForm(traversal);
         final List<Map<Object, List<Object>>> result = traversal.toList();
         assertEquals(4, result.size());
@@ -112,8 +110,8 @@
 
     @Test
     @LoadGraphWith(MODERN)
-    public void g_V_pageRank_byXoutEXknowsXX_byXfriendRankX_project_byXnameX_byXvaluesXfriendRankX_mathX() {
-        final Traversal<Vertex, Map<String, Object>> traversal = get_g_V_pageRank_byXoutEXknowsXX_byXfriendRankX_project_byXnameX_byXvaluesXfriendRankX_mathX();
+    public void g_V_pageRank_withXedges_outEXknowsXX_withXpropertyName_friendRankX_project_byXnameX_byXvaluesXfriendRankX_mathX() {
+        final Traversal<Vertex, Map<String, Object>> traversal = get_g_V_pageRank_withXedges_outEXknowsXX_withXpropertyName_friendRankX_project_byXnameX_byXvaluesXfriendRankX_mathX();
         printTraversalForm(traversal);
         int counter = 0;
         while (traversal.hasNext()) {
@@ -144,8 +142,8 @@
 
     @Test
     @LoadGraphWith(MODERN)
-    public void g_V_hasLabelXpersonX_pageRank_byXpageRankX_project_byXnameX_byXvaluesXpageRankX_mathX() {
-        final Traversal<Vertex, Map<String, Object>> traversal = get_g_V_hasLabelXpersonX_pageRank_byXpageRankX_project_byXnameX_byXvaluesXpageRankX_mathX();
+    public void g_V_hasLabelXpersonX_pageRank_withXpropertyName_pageRankX_project_byXnameX_byXvaluesXpageRankX_mathX() {
+        final Traversal<Vertex, Map<String, Object>> traversal = get_g_V_hasLabelXpersonX_pageRank_withXpropertyName_pageRankX_project_byXnameX_byXvaluesXpageRankX_mathX();
         printTraversalForm(traversal);
         int counter = 0;
         while (traversal.hasNext()) {
@@ -165,8 +163,8 @@
 
     @Test
     @LoadGraphWith(MODERN)
-    public void g_V_pageRank_byXpageRankX_asXaX_outXknowsX_pageRank_asXbX_selectXa_bX_by_byXmathX() {
-        final Traversal<Vertex, Map<String, Object>> traversal = get_g_V_pageRank_byXpageRankX_asXaX_outXknowsX_pageRank_asXbX_selectXa_bX_by_byXmathX();
+    public void g_V_pageRank_withXpropertyName_pageRankX_asXaX_outXknowsX_pageRank_asXbX_selectXa_bX_by_byXmathX() {
+        final Traversal<Vertex, Map<String, Object>> traversal = get_g_V_pageRank_withXpropertyName_pageRankX_asXaX_outXknowsX_pageRank_asXbX_selectXa_bX_by_byXmathX();
         printTraversalForm(traversal);
         int counter = 0;
         while (traversal.hasNext()) {
@@ -183,8 +181,8 @@
 
     @Test
     @LoadGraphWith(MODERN)
-    public void g_V_hasLabelXsoftwareX_hasXname_rippleX_pageRankX1X_byXinEXcreatedXX_timesX1X_byXpriorsX_inXcreatedX_unionXboth__identityX_valueMapXname_priorsX() {
-        final Traversal<Vertex, Map<Object, List<Object>>> traversal = get_g_V_hasLabelXsoftwareX_hasXname_rippleX_pageRankX1X_byXinEXcreatedXX_timesX1X_byXpriorsX_inXcreatedX_unionXboth__identityX_valueMapXname_priorsX();
+    public void g_V_hasLabelXsoftwareX_hasXname_rippleX_pageRankX1X_withXedges_inEXcreatedXX_withXtimes_1X_withXpropertyName_priorsX_inXcreatedX_unionXboth__identityX_valueMapXname_priorsX() {
+        final Traversal<Vertex, Map<Object, List<Object>>> traversal = get_g_V_hasLabelXsoftwareX_hasXname_rippleX_pageRankX1X_withXedges_inEXcreatedXX_withXtimes_1X_withXpropertyName_priorsX_inXcreatedX_unionXboth__identityX_valueMapXname_priorsX();
         printTraversalForm(traversal);
         int counter = 0;
         while (traversal.hasNext()) {
@@ -202,39 +200,6 @@
 
     @Test
     @LoadGraphWith(MODERN)
-    public void g_V_outXcreatedX_groupXmX_byXlabelX_pageRankX1X_byXpageRankX_byXinEX_timesX1X_inXcreatedX_groupXmX_byXpageRankX_capXmX() {
-        // [{2.0=[v[4], v[4], v[4], v[4]], 1.0=[v[6], v[6], v[6], v[1], v[1], v[1]], software=[v[5], v[3], v[3], v[3]]}]
-        final Traversal<Vertex, Map<Object, List<Vertex>>> traversal = get_g_V_outXcreatedX_groupXmX_byXlabelX_pageRankX1X_byXpageRankX_byXinEX_timesX1X_inXcreatedX_groupXmX_byXpageRankX_capXmX();
-        printTraversalForm(traversal);
-        final Map<Object, List<Vertex>> map = traversal.next();
-        assertFalse(traversal.hasNext());
-        assertEquals(3, map.size());
-        assertTrue(map.containsKey("software"));
-        map.forEach((k, v) -> {
-            boolean found = false;
-            if (!k.equals("software") && v.size() == 4) {
-                assertEquals(2.0d, ((Number) k).doubleValue(), 0.01d);
-                assertEquals(4, v.stream().filter(vertex -> vertex.id().equals(convertToVertexId(graph, "josh"))).count());
-                found = true;
-            } else if (v.size() == 6) {
-                assertEquals(1.0d, ((Number) k).doubleValue(), 0.01d);
-                assertEquals(3, v.stream().filter(vertex -> vertex.id().equals(convertToVertexId(graph, "peter"))).count());
-                assertEquals(3, v.stream().filter(vertex -> vertex.id().equals(convertToVertexId(graph, "marko"))).count());
-                found = true;
-            } else if (v.size() == 4) {
-                assertEquals("software", k);
-                assertEquals(3, v.stream().filter(vertex -> vertex.id().equals(convertToVertexId(graph, "lop"))).count());
-                assertEquals(1, v.stream().filter(vertex -> vertex.id().equals(convertToVertexId(graph, "ripple"))).count());
-                found = true;
-            }
-
-            if (!found)
-                fail("There are too many key/values: " + k + "--" + v);
-        });
-    }
-
-    @Test
-    @LoadGraphWith(MODERN)
     public void g_V_outXcreatedX_groupXmX_byXlabelX_pageRankX1X_withXPROPERTY_NAME_pageRankXX_withXEDGES_inEXX_withXTIMES_1X_inXcreatedX_groupXmX_byXpageRankX_capXmX() {
         // [{2.0=[v[4], v[4], v[4], v[4]], 1.0=[v[6], v[6], v[6], v[1], v[1], v[1]], software=[v[5], v[3], v[3], v[3]]}]
         final Traversal<Vertex, Map<Object, List<Vertex>>> traversal = get_g_V_outXcreatedX_groupXmX_byXlabelX_pageRankX1X_withXpropertyName_pageRankXX_withXedges_inEXX_withXtimes_1X_inXcreatedX_groupXmX_byXpageRankX_capXmX();
@@ -274,13 +239,13 @@
         }
 
         @Override
-        public Traversal<Vertex, Map<Object, List<Object>>> get_g_V_outXcreatedX_pageRank_byXbothEX_byXprojectRankX_timesX0X_valueMapXname_projectRankX() {
-            return g.V().out("created").pageRank().by(__.bothE()).by("projectRank").times(0).valueMap("name", "projectRank");
+        public Traversal<Vertex, Map<Object, List<Object>>> get_g_V_outXcreatedX_pageRank_withXedges_bothEX_withXpropertyName_projectRankXwithXtimes_0X_valueMapXname_projectRankX() {
+            return g.V().out("created").pageRank().with(PageRank.edges, __.bothE()).with(PageRank.propertyName, "projectRank").with(PageRank.times, 0).valueMap("name", "projectRank");
         }
 
         @Override
-        public Traversal<Vertex, Map<String, Object>> get_g_V_pageRank_byXoutEXknowsXX_byXfriendRankX_project_byXnameX_byXvaluesXfriendRankX_mathX() {
-            return g.V().pageRank().by(__.outE("knows")).by("friendRank").project("name", "friendRank").by("name").by(__.values("friendRank").math("ceil(_ * 100)"));
+        public Traversal<Vertex, Map<String, Object>> get_g_V_pageRank_withXedges_outEXknowsXX_withXpropertyName_friendRankX_project_byXnameX_byXvaluesXfriendRankX_mathX() {
+            return g.V().pageRank().with(PageRank.edges, __.outE("knows")).with(PageRank.propertyName, "friendRank").project("name", "friendRank").by("name").by(__.values("friendRank").math("ceil(_ * 100)"));
         }
 
         @Override
@@ -294,23 +259,18 @@
         }
 
         @Override
-        public Traversal<Vertex, Map<String, Object>> get_g_V_hasLabelXpersonX_pageRank_byXpageRankX_project_byXnameX_byXvaluesXpageRankX_mathX() {
-            return g.V().hasLabel("person").pageRank().by("pageRank").project("name", "pageRank").by("name").by(__.values("pageRank").math("ceil(_ * 100)"));
+        public Traversal<Vertex, Map<String, Object>> get_g_V_hasLabelXpersonX_pageRank_withXpropertyName_pageRankX_project_byXnameX_byXvaluesXpageRankX_mathX() {
+            return g.V().hasLabel("person").pageRank().with(PageRank.propertyName, "pageRank").project("name", "pageRank").by("name").by(__.values("pageRank").math("ceil(_ * 100)"));
         }
 
         @Override
-        public Traversal<Vertex, Map<String, Object>> get_g_V_pageRank_byXpageRankX_asXaX_outXknowsX_pageRank_asXbX_selectXa_bX_by_byXmathX() {
-            return g.V().pageRank().by("pageRank").as("a").out("knows").values("pageRank").as("b").select("a", "b").by().by(__.math("ceil(_ * 100)"));
+        public Traversal<Vertex, Map<String, Object>> get_g_V_pageRank_withXpropertyName_pageRankX_asXaX_outXknowsX_pageRank_asXbX_selectXa_bX_by_byXmathX() {
+            return g.V().pageRank().with(PageRank.propertyName, "pageRank").as("a").out("knows").values("pageRank").as("b").select("a", "b").by().by(__.math("ceil(_ * 100)"));
         }
 
         @Override
-        public Traversal<Vertex, Map<Object, List<Object>>> get_g_V_hasLabelXsoftwareX_hasXname_rippleX_pageRankX1X_byXinEXcreatedXX_timesX1X_byXpriorsX_inXcreatedX_unionXboth__identityX_valueMapXname_priorsX() {
-            return g.V().hasLabel("software").has("name", "ripple").pageRank(1.0).by(__.inE("created")).times(1).by("priors").in("created").union(__.both(), __.identity()).valueMap("name", "priors");
-        }
-
-        @Override
-        public Traversal<Vertex, Map<Object, List<Vertex>>> get_g_V_outXcreatedX_groupXmX_byXlabelX_pageRankX1X_byXpageRankX_byXinEX_timesX1X_inXcreatedX_groupXmX_byXpageRankX_capXmX() {
-            return g.V().out("created").group("m").by(T.label).pageRank(1.0).by("pageRank").by(__.inE()).times(1).in("created").group("m").by("pageRank").cap("m");
+        public Traversal<Vertex, Map<Object, List<Object>>> get_g_V_hasLabelXsoftwareX_hasXname_rippleX_pageRankX1X_withXedges_inEXcreatedXX_withXtimes_1X_withXpropertyName_priorsX_inXcreatedX_unionXboth__identityX_valueMapXname_priorsX() {
+            return g.V().hasLabel("software").has("name", "ripple").pageRank(1.0).with(PageRank.edges, __.inE("created")).with(PageRank.times, 1).with(PageRank.propertyName, "priors").in("created").union(__.both(), __.identity()).valueMap("name", "priors");
         }
 
         @Override
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PeerPressureTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PeerPressureTest.java
index 5087522..e834ecf 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PeerPressureTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PeerPressureTest.java
@@ -24,6 +24,7 @@
 import org.apache.tinkerpop.gremlin.process.AbstractGremlinProcessTest;
 import org.apache.tinkerpop.gremlin.process.GremlinProcessRunner;
 import org.apache.tinkerpop.gremlin.process.computer.clustering.peerpressure.PeerPressureVertexProgram;
+import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.PageRank;
 import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.PeerPressure;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
@@ -51,9 +52,7 @@
 
     public abstract Traversal<Vertex, Vertex> get_g_V_peerPressure_hasXclusterX();
 
-    public abstract Traversal<Vertex, Map<Object, Number>> get_g_V_peerPressure_byXclusterX_byXoutEXknowsXX_pageRankX1X_byXrankX_byXoutEXknowsXX_timesX2X_group_byXclusterX_byXrank_sumX_limitX100X();
-
-    public abstract Traversal<Vertex, Map<Object, List<Object>>> get_g_V_hasXname_rippleX_inXcreatedX_peerPressure_byXoutEX_byXclusterX_repeatXunionXidentity__bothX_timesX2X_dedup_valueMapXname_clusterX();
+    public abstract Traversal<Vertex, Map<Object, Number>> get_g_V_peerPressure_withXpropertyName_clusterX_withXedges_outEXknowsXX_pageRankX1X_withXpropertyName_rankX_withXedges_outEXknowsXX_withXtimes_2X_group_byXclusterX_byXrank_sumX_limitX100X();
 
     public abstract Traversal<Vertex, Map<Object, List<Object>>> get_g_V_hasXname_rippleX_inXcreatedX_peerPressure_withXedges_outEX_withXpropertyName_clusterX_repeatXunionXidentity__bothX_timesX2X_dedup_valueMapXname_clusterX();
 
@@ -67,8 +66,8 @@
 
     @Test
     @LoadGraphWith(MODERN)
-    public void g_V_peerPressure_byXclusterX_byXoutEXknowsXX_pageRankX1X_byXrankX_byXoutEXknowsXX_timesX2X_group_byXclusterX_byXrank_sumX() {
-        final Traversal<Vertex, Map<Object, Number>> traversal = get_g_V_peerPressure_byXclusterX_byXoutEXknowsXX_pageRankX1X_byXrankX_byXoutEXknowsXX_timesX2X_group_byXclusterX_byXrank_sumX_limitX100X();
+    public void g_V_peerPressure_withXpropertyName_clusterX_withXedges_outEXknowsXX_pageRankX1X_withXpropertyName_rankX_withXedges_outEXknowsXX_withXtimes_2X_group_byXclusterX_byXrank_sumX_limitX100X() {
+        final Traversal<Vertex, Map<Object, Number>> traversal = get_g_V_peerPressure_withXpropertyName_clusterX_withXedges_outEXknowsXX_pageRankX1X_withXpropertyName_rankX_withXedges_outEXknowsXX_withXtimes_2X_group_byXclusterX_byXrank_sumX_limitX100X();
         printTraversalForm(traversal);
         final Map<Object, Number> map = traversal.next();
         assertFalse(traversal.hasNext());
@@ -81,29 +80,7 @@
 
     @Test
     @LoadGraphWith(MODERN)
-    public void g_V_hasXname_rippleX_inXcreatedX_peerPressure_byXoutEX_byXclusterX_repeatXunionXidentity__bothX_timesX2X_dedup_valueMapXname_clusterX() {
-        TestHelper.assumeNonDeterministic();
-        final Traversal<Vertex, Map<Object, List<Object>>> traversal = get_g_V_hasXname_rippleX_inXcreatedX_peerPressure_byXoutEX_byXclusterX_repeatXunionXidentity__bothX_timesX2X_dedup_valueMapXname_clusterX();
-        printTraversalForm(traversal);
-        final List<Map<Object, List<Object>>> results = traversal.toList();
-        assertEquals(6, results.size());
-        final Map<String, Object> clusters = new HashMap<>();
-        results.forEach(m -> clusters.put((String) m.get("name").get(0), m.get("cluster").get(0)));
-        assertEquals(2, results.get(0).size());
-        assertEquals(6, clusters.size());
-        assertEquals(clusters.get("josh"), clusters.get("ripple"));
-        assertEquals(clusters.get("josh"), clusters.get("lop"));
-        final Set<Object> ids = new HashSet<>(clusters.values());
-        assertEquals(4, ids.size());
-        assertTrue(ids.contains(convertToVertexId("marko")));
-        assertTrue(ids.contains(convertToVertexId("vadas")));
-        assertTrue(ids.contains(convertToVertexId("josh")));
-        assertTrue(ids.contains(convertToVertexId("peter")));
-    }
-
-    @Test
-    @LoadGraphWith(MODERN)
-    public void g_V_hasXname_rippleX_inXcreatedX_peerPressure_withXEDGES_outEX_withXPROPERTY_NAME_clusterX_repeatXunionXidentity__bothX_timesX2X_dedup_valueMapXname_clusterX() {
+    public void g_V_hasXname_rippleX_inXcreatedX_peerPressure_withXedges_outEX_withXpropertyName_clusterX_repeatXunionXidentity__bothX_timesX2X_dedup_valueMapXname_clusterX() {
         TestHelper.assumeNonDeterministic();
         final Traversal<Vertex, Map<Object, List<Object>>> traversal = get_g_V_hasXname_rippleX_inXcreatedX_peerPressure_withXedges_outEX_withXpropertyName_clusterX_repeatXunionXidentity__bothX_timesX2X_dedup_valueMapXname_clusterX();
         printTraversalForm(traversal);
@@ -131,13 +108,8 @@
         }
 
         @Override
-        public Traversal<Vertex, Map<Object, Number>> get_g_V_peerPressure_byXclusterX_byXoutEXknowsXX_pageRankX1X_byXrankX_byXoutEXknowsXX_timesX2X_group_byXclusterX_byXrank_sumX_limitX100X() {
-            return g.V().peerPressure().by("cluster").by(__.outE("knows")).pageRank(1.0d).by("rank").by(__.outE("knows")).times(1).<Object, Number>group().by("cluster").by(__.values("rank").sum()).limit(100);
-        }
-
-        @Override
-        public Traversal<Vertex, Map<Object, List<Object>>> get_g_V_hasXname_rippleX_inXcreatedX_peerPressure_byXoutEX_byXclusterX_repeatXunionXidentity__bothX_timesX2X_dedup_valueMapXname_clusterX() {
-            return g.V().has("name", "ripple").in("created").peerPressure().by(__.outE()).by("cluster").repeat(__.union(__.identity(), __.both())).times(2).dedup().valueMap("name", "cluster");
+        public Traversal<Vertex, Map<Object, Number>> get_g_V_peerPressure_withXpropertyName_clusterX_withXedges_outEXknowsXX_pageRankX1X_withXpropertyName_rankX_withXedges_outEXknowsXX_withXtimes_2X_group_byXclusterX_byXrank_sumX_limitX100X() {
+            return g.V().peerPressure().with(PeerPressure.propertyName, "cluster").with(PeerPressure.edges, __.outE("knows")).pageRank(1.0d).with(PageRank.propertyName, "rank").with(PageRank.edges, __.outE("knows")).with(PageRank.times, 1).<Object, Number>group().by("cluster").by(__.values("rank").sum()).limit(100);
         }
 
         @Override
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProfileTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProfileTest.java
index b7985e6..9747fc0 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProfileTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProfileTest.java
@@ -23,6 +23,7 @@
 import org.apache.tinkerpop.gremlin.process.AbstractGremlinProcessTest;
 import org.apache.tinkerpop.gremlin.process.GremlinProcessRunner;
 import org.apache.tinkerpop.gremlin.process.IgnoreEngine;
+import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.PageRank;
 import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.TraversalVertexProgramStep;
 import org.apache.tinkerpop.gremlin.process.traversal.P;
 import org.apache.tinkerpop.gremlin.process.traversal.Step;
@@ -92,7 +93,7 @@
 
     public abstract Traversal<Vertex, Map<String, String>> get_g_V_matchXa_created_b__b_in_count_isXeqX1XXX_selectXa_bX_profileXmetricsX();
 
-    public abstract Traversal<Vertex, TraversalMetrics> get_g_V_hasLabelXpersonX_pageRank_byXrankX_byXbothEX_rank_profile();
+    public abstract Traversal<Vertex, TraversalMetrics> get_g_V_hasLabelXpersonX_pageRank_withXpropertyName_rankX_withXedges_bothEX_rank_profile();
 
     public abstract Traversal<Vertex, TraversalMetrics> get_g_V_groupXmX_profile();
 
@@ -265,8 +266,8 @@
 
         final TraversalMetrics traversalMetrics = traversal.next();
         validate_g_V_repeat_both_modern_profile(traversalMetrics,
-                traversal.asAdmin().getStrategies().toList().contains(RepeatUnrollStrategy.instance()) &&
-                        !traversal.asAdmin().getStrategies().toList().contains(ComputerVerificationStrategy.instance()));
+                traversal.asAdmin().getStrategies().getStrategy(RepeatUnrollStrategy.class).isPresent() &&
+                        !traversal.asAdmin().getStrategies().getStrategy(ComputerVerificationStrategy.class).isPresent());
     }
 
     @Test
@@ -277,8 +278,8 @@
         traversal.iterate();
         final TraversalMetrics traversalMetrics = traversal.asAdmin().getSideEffects().get(METRICS_KEY);
         validate_g_V_repeat_both_modern_profile(traversalMetrics,
-                traversal.asAdmin().getStrategies().toList().contains(RepeatUnrollStrategy.instance()) &&
-                        !traversal.asAdmin().getStrategies().toList().contains(ComputerVerificationStrategy.instance()));
+                traversal.asAdmin().getStrategies().getStrategy(RepeatUnrollStrategy.class).isPresent() &&
+                        !traversal.asAdmin().getStrategies().getStrategy(ComputerVerificationStrategy.class).isPresent());
     }
 
     private void validate_g_V_repeat_both_modern_profile(final TraversalMetrics traversalMetrics, final boolean withRepeatUnrollStrategy) {
@@ -333,7 +334,7 @@
         assertEquals(1, metrics.getCount(TraversalMetrics.TRAVERSER_COUNT_ID).longValue());
         assertEquals(1, metrics.getCount(TraversalMetrics.ELEMENT_COUNT_ID).longValue());
 
-        if (traversal.asAdmin().getStrategies().toList().stream().anyMatch(s -> s instanceof CountStrategy)) {
+        if (traversal.asAdmin().getStrategies().getStrategy(CountStrategy.class).isPresent()) {
             assertEquals("Metrics 1 should have 4 nested metrics.", 4, metrics.getNested().size());
         } else {
             assertEquals("Metrics 1 should have 3 nested metrics.", 3, metrics.getNested().size());
@@ -435,8 +436,8 @@
     @Test
     @LoadGraphWith(MODERN)
     @IgnoreEngine(TraversalEngine.Type.STANDARD)
-    public void g_V_hasLabelXpersonX_pageRank_byXrankX_byXbothEX_rank_profile() {
-        final Traversal<Vertex, TraversalMetrics> traversal = get_g_V_hasLabelXpersonX_pageRank_byXrankX_byXbothEX_rank_profile();
+    public void g_V_hasLabelXpersonX_pageRank_withXpropertyName_rankX_withXedges_bothEX_rank_profile() {
+        final Traversal<Vertex, TraversalMetrics> traversal = get_g_V_hasLabelXpersonX_pageRank_withXpropertyName_rankX_withXedges_bothEX_rank_profile();
         //printTraversalForm(traversal);
         try {
             traversal.iterate();
@@ -539,8 +540,8 @@
         }
 
         @Override
-        public Traversal<Vertex, TraversalMetrics> get_g_V_hasLabelXpersonX_pageRank_byXrankX_byXbothEX_rank_profile() {
-            return g.V().hasLabel("person").pageRank().by("rank").by(__.bothE()).values("rank").profile();
+        public Traversal<Vertex, TraversalMetrics> get_g_V_hasLabelXpersonX_pageRank_withXpropertyName_rankX_withXedges_bothEX_rank_profile() {
+            return g.V().hasLabel("person").pageRank().with(PageRank.propertyName, "rank").with(PageRank.edges, __.bothE()).values("rank").profile();
         }
 
         @Override
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProgramTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProgramTest.java
index a0c5b23..1439a7b 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProgramTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProgramTest.java
@@ -19,7 +19,7 @@
 
 package org.apache.tinkerpop.gremlin.process.traversal.step.map;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.LoadGraphWith;
 import org.apache.tinkerpop.gremlin.process.AbstractGremlinProcessTest;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectTest.java
index 470513c..cd274d0 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectTest.java
@@ -26,6 +26,7 @@
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
 import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.T;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -155,6 +156,10 @@
 
     public abstract Traversal<Vertex, Vertex> get_g_VX1X_asXaX_repeatXout_asXaXX_timesX2X_selectXlast_aX(final Object v1Id);
 
+    public abstract Traversal<Edge, Object> get_g_EX11X_propertiesXweightX_asXaX_selectXaX_byXkeyX(final Object e11Id);
+
+    public abstract Traversal<Edge, Object> get_g_EX11X_propertiesXweightX_asXaX_selectXaX_byXvalueX(final Object e11Id);
+
     // when labels don't exist
 
     public abstract Traversal<Vertex, String> get_g_V_untilXout_outX_repeatXin_asXaXX_selectXaX_byXtailXlocalX_nameX();
@@ -713,6 +718,22 @@
         assertEquals(Collections.emptyList(), traversal.toList());
     }
 
+    @Test
+    @LoadGraphWith(MODERN)
+    public void g_EX11X_propertiesXweightX_asXaX_selectXaX_byXkeyX() {
+        final Traversal<Edge, Object> traversal = get_g_EX11X_propertiesXweightX_asXaX_selectXaX_byXkeyX(convertToEdgeId("josh", "created", "lop"));
+        printTraversalForm(traversal);
+        assertEquals("weight", traversal.next());
+    }
+
+    @Test
+    @LoadGraphWith(MODERN)
+    public void g_EX11X_propertiesXweightX_asXaX_selectXaX_byXvalueX() {
+        final Traversal<Edge, Object> traversal = get_g_EX11X_propertiesXweightX_asXaX_selectXaX_byXvalueX(convertToEdgeId("josh", "created", "lop"));
+        printTraversalForm(traversal);
+        assertEquals(0.4d, (double) traversal.next(), 0.0001d);
+    }
+
     // when labels don't exist
 
     @Test
@@ -1112,6 +1133,16 @@
             return g.V().as("a").where(__.out("knows")).<Vertex>select("a");
         }
 
+        @Override
+        public Traversal<Edge, Object> get_g_EX11X_propertiesXweightX_asXaX_selectXaX_byXkeyX(final Object e11Id) {
+            return g.E(e11Id).properties("weight").as("a").select("a").by(T.key);
+        }
+
+        @Override
+        public Traversal<Edge, Object> get_g_EX11X_propertiesXweightX_asXaX_selectXaX_byXvalueX(final Object e11Id) {
+            return g.E(e11Id).properties("weight").as("a").select("a").by(T.value);
+        }
+
         // select columns test
 
         @Override
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/VertexTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/VertexTest.java
index ec3c721..b5f3145 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/VertexTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/VertexTest.java
@@ -45,7 +45,7 @@
 import static org.hamcrest.Matchers.containsInAnyOrder;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertTrue;
 
 /**
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/WriteTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/WriteTest.java
index 9798095..cfd9e09 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/WriteTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/WriteTest.java
@@ -34,7 +34,7 @@
 
 import static org.hamcrest.core.Is.is;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 
 /**
  * @author Stephen Mallette (http://stephen.genoprime.com)
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateTest.java
index f780046..6ff49c9 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateTest.java
@@ -44,7 +44,7 @@
 import static org.hamcrest.core.Is.is;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeThat;
 
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupCountTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupCountTest.java
index 34011ac..1051e2a 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupCountTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupCountTest.java
@@ -30,7 +30,9 @@
 import org.junit.runner.RunWith;
 
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.MODERN;
@@ -76,6 +78,8 @@
 
     public abstract Traversal<Vertex, String> get_g_V_both_groupCountXaX_byXlabelX_asXbX_barrier_whereXselectXaX_selectXsoftwareX_isXgtX2XXX_selectXbX_name();
 
+    public abstract Traversal<Vertex, Map<Object, Long>> get_g_V_hasXperson_name_markoX_bothXknowsX_groupCount_byXvaluesXnameX_foldX();
+
     @Test
     @LoadGraphWith(MODERN)
     public void g_V_outXcreatedX_groupCount_byXnameX() {
@@ -258,6 +262,18 @@
         checkSideEffects(traversal.asAdmin().getSideEffects(), "a", HashMap.class);
     }
 
+    @Test
+    @LoadGraphWith(MODERN)
+    public void g_V_hasXperson_name_markoX_bothXknowsX_groupCount_byXvaluesXnameX_foldX() {
+        final Traversal<Vertex, Map<Object,Long>> traversal = get_g_V_hasXperson_name_markoX_bothXknowsX_groupCount_byXvaluesXnameX_foldX();
+        printTraversalForm(traversal);
+        final Map<Object,Long> map = traversal.next();
+        assertFalse(traversal.hasNext());
+        assertEquals(2, map.size());
+        assertEquals(1L, map.get(Collections.singletonList("josh")).longValue());
+        assertEquals(1L, map.get(Collections.singletonList("vadas")).longValue());
+    }
+
     public static class Traversals extends GroupCountTest {
 
         @Override
@@ -326,5 +342,10 @@
         public Traversal<Vertex, String> get_g_V_both_groupCountXaX_byXlabelX_asXbX_barrier_whereXselectXaX_selectXsoftwareX_isXgtX2XXX_selectXbX_name() {
             return g.V().both().groupCount("a").by(T.label).as("b").barrier().where(__.select("a").select("software").is(gt(2))).select("b").values("name");
         }
+
+        @Override
+        public Traversal<Vertex, Map<Object, Long>> get_g_V_hasXperson_name_markoX_bothXknowsX_groupCount_byXvaluesXnameX_foldX() {
+            return g.V().has("person", "name", "marko").both("knows").groupCount().by(__.values("name").fold());
+        }
     }
 }
\ No newline at end of file
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupTest.java
index 5b0cf32..c7f86d7 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupTest.java
@@ -59,6 +59,8 @@
 
     public abstract Traversal<Vertex, Map<String, Collection<Vertex>>> get_g_V_group_byXnameX();
 
+    public abstract Traversal<Vertex, Map<Integer, Collection<Vertex>>> get_g_V_group_byXageX();
+
     public abstract Traversal<Vertex, Map<String, Collection<Vertex>>> get_g_V_group_byXnameX_by();
 
     public abstract Traversal<Vertex, Map<String, Collection<Vertex>>> get_g_V_groupXaX_byXnameX_capXaX();
@@ -101,6 +103,10 @@
 
     public abstract Traversal<Vertex, Map<String, Number>> get_g_V_hasLabelXpersonX_asXpX_outXcreatedX_group_byXnameX_byXselectXpX_valuesXageX_sumX();
 
+    public abstract Traversal<Vertex, Map<String, Long>> get_g_V_group_byXlabelX_byXlabel_countX();
+
+    public abstract Traversal<Vertex, Map<String, Long>> get_g_V_groupXmX_byXlabelX_byXlabel_countX_capXmX();
+
     @Test
     @LoadGraphWith(MODERN)
     public void g_V_group_byXnameX() {
@@ -110,6 +116,24 @@
         checkSideEffects(traversal.asAdmin().getSideEffects());
     }
 
+    @Test
+    @LoadGraphWith(MODERN)
+    public void g_V_group_byXageX() {
+        final Traversal<Vertex, Map<Integer, Collection<Vertex>>> traversal = get_g_V_group_byXageX();
+        printTraversalForm(traversal);
+
+        final Map<Integer, Collection<Vertex>> map = traversal.next();
+        assertEquals(5, map.size());
+        map.forEach((key, values) -> {
+            if (null == key)
+                assertEquals(2, values.size());
+            else
+                assertEquals(1, values.size());
+        });
+        assertFalse(traversal.hasNext());
+
+        checkSideEffects(traversal.asAdmin().getSideEffects());
+    }
 
     @Test
     @LoadGraphWith(MODERN)
@@ -129,7 +153,7 @@
         checkSideEffects(traversal.asAdmin().getSideEffects(), "a", HashMap.class);
     }
 
-    private void assertCommonA(Traversal<Vertex, Map<String, Collection<Vertex>>> traversal) {
+    private void assertCommonA(final Traversal<Vertex, Map<String, Collection<Vertex>>> traversal) {
         final Map<String, Collection<Vertex>> map = traversal.next();
         assertEquals(6, map.size());
         map.forEach((key, values) -> {
@@ -499,6 +523,32 @@
         assertFalse(traversal.hasNext());
     }
 
+    @Test
+    @LoadGraphWith(MODERN)
+    public void g_V_group_byXlabelX_byXlabel_countX() {
+        final Traversal<Vertex, Map<String, Long>> traversal = get_g_V_group_byXlabelX_byXlabel_countX();
+        printTraversalForm(traversal);
+        final Map<String, Long> map = traversal.next();
+        assertEquals(2, map.size());
+        assertTrue(map.containsKey("person"));
+        assertTrue(map.containsKey("software"));
+        assertEquals(4L, map.get("person").longValue());
+        assertEquals(2L, map.get("software").longValue());
+    }
+
+    @Test
+    @LoadGraphWith(MODERN)
+    public void g_V_groupXmX_byXlabelX_byXlabel_countX_capXmX() {
+        final Traversal<Vertex, Map<String, Long>> traversal = get_g_V_groupXmX_byXlabelX_byXlabel_countX_capXmX();
+        printTraversalForm(traversal);
+        final Map<String, Long> map = traversal.next();
+        assertEquals(2, map.size());
+        assertTrue(map.containsKey("person"));
+        assertTrue(map.containsKey("software"));
+        assertEquals(4L, map.get("person").longValue());
+        assertEquals(2L, map.get("software").longValue());
+    }
+
     public static class Traversals extends GroupTest {
 
         @Override
@@ -507,6 +557,11 @@
         }
 
         @Override
+        public Traversal<Vertex, Map<Integer, Collection<Vertex>>> get_g_V_group_byXageX() {
+            return g.V().<Integer, Collection<Vertex>>group().by("age");
+        }
+
+        @Override
         public Traversal<Vertex, Map<String, Collection<Vertex>>> get_g_V_group_byXnameX_by() {
             return g.V().<String, Collection<Vertex>>group().by("name").by();
         }
@@ -610,5 +665,15 @@
         public Traversal<Vertex, Map<String, Number>> get_g_V_hasLabelXpersonX_asXpX_outXcreatedX_group_byXnameX_byXselectXpX_valuesXageX_sumX() {
             return g.V().hasLabel("person").as("p").out("created").<String, Number>group().by("name").by(__.select("p").values("age").sum());
         }
+
+        @Override
+        public Traversal<Vertex, Map<String, Long>> get_g_V_group_byXlabelX_byXlabel_countX() {
+            return g.V().<String, Long>group().by(__.label()).by(__.label().count());
+        }
+
+        @Override
+        public Traversal<Vertex, Map<String, Long>> get_g_V_groupXmX_byXlabelX_byXlabel_countX_capXmX() {
+            return g.V().group("m").by(__.label()).by(__.label().count()).cap("m");
+        }
     }
 }
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/InjectTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/InjectTest.java
index d3fc1ed..fd752d2 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/InjectTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/InjectTest.java
@@ -23,6 +23,7 @@
 import org.apache.tinkerpop.gremlin.process.GremlinProcessRunner;
 import org.apache.tinkerpop.gremlin.process.traversal.Path;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.MapHelper;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.junit.Test;
@@ -48,6 +49,12 @@
 
     public abstract Traversal<Vertex, String> get_g_VX1X_injectXg_VX4XX_out_name(final Object v1Id, final Object v4Id);
 
+    public abstract Traversal<Integer, Integer> get_g_injectXnull_1_3_nullX();
+
+    public abstract Traversal<Integer, Map<String, Object>> get_g_injectX10_20_null_20_10_10X_groupCountXxX_dedup_asXyX_projectXa_bX_by_byXselectXxX_selectXselectXyXXX();
+
+    public abstract Traversal<Map<String,Object>, Map<String, Object>> get_g_injectXname_marko_age_nullX_selectXname_ageX();
+
     @Test
     @LoadGraphWith(MODERN)
     public void g_VX1X_out_injectXv2X_name() {
@@ -85,6 +92,30 @@
     }
 
     @Test
+    public void g_injectXnull_1_3_nullX() {
+        final Traversal<Integer, Integer> traversal = get_g_injectXnull_1_3_nullX();
+        printTraversalForm(traversal);
+        checkResults(Arrays.asList(null, 1, 3, null), traversal);
+    }
+
+    @Test
+    public void g_injectX10_20_null_20_10_10X_groupCountXxX_dedup_asXyX_projectXa_bX_by_byXselectXxX_selectXselectXyXXX() {
+        final Traversal<Integer, Map<String, Object>> traversal = get_g_injectX10_20_null_20_10_10X_groupCountXxX_dedup_asXyX_projectXa_bX_by_byXselectXxX_selectXselectXyXXX();
+        printTraversalForm(traversal);
+        checkResults(makeMapList(2,
+                "a", 10, "b", 3L,
+                    "a", 20, "b", 2L,
+                    "a", null, "b", 1L), traversal);
+    }
+
+    @Test
+    public void g_injectXname_marko_age_nullX_selectXname_ageX() {
+        final Traversal<Map<String, Object>, Map<String, Object>> traversal = get_g_injectXname_marko_age_nullX_selectXname_ageX();
+        printTraversalForm(traversal);
+        checkResults(makeMapList(2, "name", "marko", "age", null), traversal);
+    }
+
+    @Test
     @LoadGraphWith(MODERN)
     public void g_VX1X_injectXg_VX4XX_out_name() {
         final Traversal<Vertex, String> traversal = get_g_VX1X_injectXg_VX4XX_out_name(convertToVertexId("marko"), convertToVertexId("josh"));
@@ -108,5 +139,27 @@
         public Traversal<Vertex, String> get_g_VX1X_injectXg_VX4XX_out_name(final Object v1Id, final Object v4Id) {
             return g.V(v1Id).inject(g.V(v4Id).next()).out().values("name");
         }
+
+        @Override
+        public Traversal<Integer, Integer> get_g_injectXnull_1_3_nullX() {
+            return g.inject(null, 1, 3, null);
+        }
+
+        @Override
+        public Traversal<Integer, Map<String, Object>> get_g_injectX10_20_null_20_10_10X_groupCountXxX_dedup_asXyX_projectXa_bX_by_byXselectXxX_selectXselectXyXXX() {
+            return g.inject(10,20,null,20,10,10).groupCount("x").
+                     dedup().as("y").
+                     project("a","b").
+                       by().
+                       by(__.select("x").select(__.select("y")));
+        }
+
+        @Override
+        public Traversal<Map<String, Object>, Map<String, Object>> get_g_injectXname_marko_age_nullX_selectXname_ageX() {
+            final Map<String,Object> m = new HashMap<>();
+            m.put("name", "marko");
+            m.put("age", null);
+            return g.inject(m).select("name","age");
+        }
     }
 }
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SubgraphTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SubgraphTest.java
index 51d8870..9f14d15 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SubgraphTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SubgraphTest.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.FeatureRequirement;
 import org.apache.tinkerpop.gremlin.LoadGraphWith;
 import org.apache.tinkerpop.gremlin.process.AbstractGremlinProcessTest;
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/PartitionStrategyProcessTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/PartitionStrategyProcessTest.java
index f552022..b3bcf70 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/PartitionStrategyProcessTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/PartitionStrategyProcessTest.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration;
 
-import org.apache.commons.configuration.MapConfiguration;
+import org.apache.commons.configuration2.MapConfiguration;
 import org.apache.tinkerpop.gremlin.FeatureRequirement;
 import org.apache.tinkerpop.gremlin.FeatureRequirementSet;
 import org.apache.tinkerpop.gremlin.process.AbstractGremlinProcessTest;
@@ -43,7 +43,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.fail;
 
 /**
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SeedStrategyProcessTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SeedStrategyProcessTest.java
new file mode 100644
index 0000000..0f0c069
--- /dev/null
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SeedStrategyProcessTest.java
@@ -0,0 +1,105 @@
+/*
+ * 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.strategy.decoration;
+
+import org.apache.tinkerpop.gremlin.LoadGraphWith;
+import org.apache.tinkerpop.gremlin.process.AbstractGremlinProcessTest;
+import org.apache.tinkerpop.gremlin.process.GremlinProcessRunner;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+import java.util.function.Supplier;
+
+import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.GRATEFUL;
+import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.MODERN;
+import static org.apache.tinkerpop.gremlin.process.traversal.Order.shuffle;
+import static org.apache.tinkerpop.gremlin.process.traversal.Scope.local;
+import static org.junit.Assert.assertEquals;
+
+@RunWith(GremlinProcessRunner.class)
+public class SeedStrategyProcessTest extends AbstractGremlinProcessTest {
+    private static final SeedStrategy seedStrategy = new SeedStrategy(1235L);
+
+    @Test
+    @LoadGraphWith(MODERN)
+    public void shouldSeedCoin() {
+        final GraphTraversalSource gSeeded = create();
+        final List<Object> names = gSeeded.V().order().by("name").values("name").coin(0.31).order().toList();
+        repeatAssert(() -> {
+            assertEquals(names, gSeeded.V().order().by("name").values("name").coin(0.31).order().toList());
+            return null;
+        });
+    }
+
+    @Test
+    @LoadGraphWith(MODERN)
+    public void shouldSeedGlobalOrderShuffle() {
+        final GraphTraversalSource gSeeded = create();
+        final List<Object> names = gSeeded.V().order().by("name").values("name").order().by(shuffle).toList();
+        repeatAssert(() -> {
+            assertEquals(names, gSeeded.V().order().by("name").values("name").order().by(shuffle).toList());
+            return null;
+        });
+    }
+
+    @Test
+    @LoadGraphWith(MODERN)
+    public void shouldSeedLocalOrderShuffle() {
+        final GraphTraversalSource gSeeded = create();
+        final List<Object> names = gSeeded.V().order().by("name").values("name").fold().order(local).by(shuffle).next();
+        repeatAssert(() -> {
+            assertEquals(names, gSeeded.V().order().by("name").values("name").fold().order(local).by(shuffle).next());
+            return null;
+        });
+    }
+
+    @Test
+    @LoadGraphWith(GRATEFUL)
+    public void shouldSeedGlobalSample() {
+        final GraphTraversalSource gSeeded = create();
+        final List<Object> names = gSeeded.V().order().by("name").values("name").sample(20).toList();
+        repeatAssert(() -> {
+            assertEquals(names, gSeeded.V().order().by("name").values("name").sample(20).toList());
+            return null;
+        });
+    }
+
+    @Test
+    @LoadGraphWith(GRATEFUL)
+    public void shouldSeedLocalSample() {
+        final GraphTraversalSource gSeeded = create();
+        final List<Object> names = gSeeded.V().order().by("name").values("name").fold().sample(local,20).next();
+        repeatAssert(() -> {
+            assertEquals(names, gSeeded.V().order().by("name").values("name").fold().sample(local,20).next());
+            return null;
+        });
+    }
+
+    private void repeatAssert(final Supplier<Void> assertion) {
+        for (int ix = 0; ix < 128; ix++) {
+            assertion.get();
+        }
+    }
+
+    private GraphTraversalSource create() {
+        return g.withStrategies(seedStrategy);
+    }
+}
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategyProcessTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategyProcessTest.java
index cf1c790..7bb4fa9 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategyProcessTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategyProcessTest.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration;
 
-import org.apache.commons.configuration.MapConfiguration;
+import org.apache.commons.configuration2.MapConfiguration;
 import org.apache.tinkerpop.gremlin.LoadGraphWith;
 import org.apache.tinkerpop.gremlin.process.AbstractGremlinProcessTest;
 import org.apache.tinkerpop.gremlin.process.GremlinProcessRunner;
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/TranslationStrategy.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/TranslationStrategy.java
index fcecf9e..5f3458e 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/TranslationStrategy.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/TranslationStrategy.java
@@ -60,6 +60,7 @@
             PartitionStrategy.class,
             RequirementsStrategy.class,
             SackStrategy.class,
+            SeedStrategy.class,
             SideEffectStrategy.class,
             SubgraphStrategy.class,
             RemoteStrategy.class,
@@ -73,7 +74,7 @@
 
     @Override
     public void apply(final Traversal.Admin<?, ?> traversal) {
-        if (!(traversal.getParent() instanceof EmptyStep))
+        if (!(traversal.isRoot()) || traversal.getBytecode().isEmpty())
             return;
 
         final Traversal.Admin<?, ?> translatedTraversal;
@@ -134,7 +135,9 @@
             final Object[] newArgs = new Object[args.length];
 
             for (int i = 0; i < args.length; i++) {
-                if (args[i].equals("knows"))
+                if (args[i] == null)
+                    newArgs[i] = null;
+                else if (args[i].equals("knows"))
                     newArgs[i] = new Bytecode.Binding<>("a", "knows");
                 else if (args[i].equals("created"))
                     newArgs[i] = new Bytecode.Binding<>("b", "created");
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/EarlyLimitStrategyProcessTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/EarlyLimitStrategyProcessTest.java
index 8a640e2..2bf5c42 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/EarlyLimitStrategyProcessTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/EarlyLimitStrategyProcessTest.java
@@ -35,8 +35,9 @@
 import java.util.Map;
 
 import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.GRATEFUL;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
 /**
@@ -90,18 +91,22 @@
         assumeTrue("The following assertions apply to TinkerGraph only as provider strategies can alter the " +
                         "steps to not comply with expectations", graph.getClass().getSimpleName().equals("TinkerGraph"));
 
-        if (t.asAdmin().getStrategies().toList().stream().anyMatch(s -> s instanceof EarlyLimitStrategy)) {
+        if (t.asAdmin().getStrategies().getStrategy(EarlyLimitStrategy.class).isPresent()) {
             assertEquals(10, metrics.getMetrics().size());
-            assertTrue(metrics.getMetrics(5).getName().endsWith("@[d]"));
+            assertThat(metrics.getMetrics(5).getName().endsWith("@[d]"), is(true));
             assertEquals("RangeGlobalStep(0,1)", metrics.getMetrics(6).getName());
             assertEquals("PathStep@[e]", metrics.getMetrics(7).getName());
-            assertTrue(metrics.getMetrics(7).getCounts().values().stream().noneMatch(x -> x != 1L));
+            assertThat(metrics.getMetrics(7).getCounts().values().stream().allMatch(x -> x == 1L), is(true));
         } else {
             assertEquals(11, metrics.getMetrics().size());
             assertEquals("RangeGlobalStep(0,5)@[d]", metrics.getMetrics(6).getName());
             assertEquals("PathStep", metrics.getMetrics(7).getName());
             assertEquals("RangeGlobalStep(0,1)@[e]", metrics.getMetrics(8).getName());
-            assertTrue(metrics.getMetrics(7).getCounts().values().stream().allMatch(x -> x != 1L));
+            // the following used to get 2 for the count but after 17b35aa295f7e84f26fd75f8a82fc7e1c33f73f0 we stopped
+            // forward pulling an extra traverser, so pretty sure the correct assertion is to match what happens with
+            // EarlyLimitStrategy above. i'm not even sure there is a point to asserting this anymore as the original
+            // intent does not appear clear to me, but i will leave it for now.
+            // assertThat(metrics.getMetrics(7).getCounts().values().stream().allMatch(x -> x == 1L), is(true));
         }
     }
 }
\ No newline at end of file
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/server/KdcFixture.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/server/KdcFixture.java
new file mode 100644
index 0000000..637bfe7
--- /dev/null
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/server/KdcFixture.java
@@ -0,0 +1,202 @@
+/*
+ * 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.server;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.client.KrbClient;
+import org.apache.kerby.kerberos.kerb.client.KrbConfig;
+import org.apache.kerby.kerberos.kerb.client.KrbConfigKey;
+import org.apache.kerby.kerberos.kerb.server.SimpleKdcServer;
+import org.apache.kerby.kerberos.kerb.type.ticket.TgtTicket;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.net.Inet4Address;
+
+
+/**
+ * This class is derived from the following classes from https://github.com/apache/directory-kerby/blob/kerby-all-1.0.0-RC2:
+ *  - org.apache.kerby.kerberos.kerb.server.TestKdcServer
+ *  - org.apache.kerby.kerberos.kerb.server.KdcTestBase
+ *  - org.apache.kerby.kerberos.kerb.server.LoginTestBase
+ *
+ * See also: gremlin-server/src/main/static/NOTICE
+ *
+ * @author Marc de Lignie
+ */
+public class KdcFixture {
+
+    private static final org.slf4j.Logger logger = LoggerFactory.getLogger(KdcFixture.class);
+
+    final String clientPassword = "123456";
+    final String clientPassword2 = "1234562";
+    final String userPassword = "password";
+    final String clientPrincipalName = "drankye";
+    final String clientPrincipalName2 = "drankye2";
+    final String userPrincipalName = "stephen";
+    final String serverPrincipalName = "test-service";
+    final String ticketCacheFileName = "test-tkt.cc";
+    final String ticketCacheFileName2 = "test-tkt2.cc";
+    final String serviceKeytabFileName = "test-service.keytab";
+
+    final String clientPrincipal;
+    final String clientPrincipal2;
+    final String serverPrincipal;
+    final String userPrincipal;
+    final File testDir;
+    final File ticketCacheFile;
+    final File ticketCacheFile2;
+    final File serviceKeytabFile;
+
+    final String gremlinHostname;
+    final String kdcHostname;
+    private SimpleKdcServer kdcServer;
+
+    public KdcFixture(final String moduleBaseDir) {
+        this(moduleBaseDir, "localhost");
+    }
+
+    public KdcFixture(final String moduleBaseDir, final String kdcHostName) {
+        this.kdcHostname = kdcHostName;
+        gremlinHostname = findHostname();
+        serverPrincipal = serverPrincipalName + "/" + gremlinHostname + "@" + KdcFixture.TestKdcServer.KDC_REALM;
+        clientPrincipal = clientPrincipalName + "@" + KdcFixture.TestKdcServer.KDC_REALM;
+        clientPrincipal2 = clientPrincipalName2 + "@" + KdcFixture.TestKdcServer.KDC_REALM;
+        userPrincipal = userPrincipalName  + "@" + KdcFixture.TestKdcServer.KDC_REALM;
+
+        final File targetDir = new File(moduleBaseDir, "target");
+        testDir = new File(targetDir, "kdc");
+        testDir.mkdirs();
+        ticketCacheFile = new File(testDir, ticketCacheFileName);
+        ticketCacheFile2 = new File(testDir, ticketCacheFileName2);
+        serviceKeytabFile = new File(testDir, serviceKeytabFileName);
+    }
+
+    private String findHostname() {
+        // Hostname setting must be consistent with the way gremlin-console sets gremlin-server's hostname
+        // and derives gremlin-server's principal name. Also, the hostname needs to be lowercase for use
+        // in principal names.
+        String hostname = "";
+        try {
+            hostname = Inet4Address.getLocalHost().getCanonicalHostName().toLowerCase();
+        } catch (Exception e) {
+            logger.error("Hostname not found: " + e.getMessage());
+        }
+        return hostname;
+    }
+
+    private class TestKdcServer extends SimpleKdcServer {
+        public static final String KDC_REALM = "TEST.COM";
+        public final String HOSTNAME = kdcHostname;
+        public static final int KDC_PORT = 4588;
+
+        TestKdcServer() throws KrbException {
+            setKdcRealm(KDC_REALM);
+            setKdcHost(HOSTNAME);
+            setAllowTcp(true);
+            setAllowUdp(true);
+            setKdcTcpPort(KDC_PORT);
+            setKdcUdpPort(KDC_PORT);
+
+            final KrbClient krbClnt = getKrbClient();
+            final KrbConfig krbConfig = krbClnt.getKrbConfig();
+            krbConfig.setString(KrbConfigKey.PERMITTED_ENCTYPES,
+                    "aes128-cts-hmac-sha1-96 des-cbc-crc des-cbc-md5 des3-cbc-sha1");
+            krbConfig.setString(KrbConfigKey.DEFAULT_REALM, KDC_REALM);
+            krbClnt.setTimeout(10 * 1000);
+        }
+    }
+
+    public void setUp() throws Exception {
+        setUpKdcServer();
+        setUpPrincipals();
+    }
+
+    private void setUpKdcServer() throws Exception {
+        kdcServer = new TestKdcServer();
+        kdcServer.setWorkDir(testDir);
+        kdcServer.init();
+        kdcServer.start();
+    }
+
+    private void setUpPrincipals() throws KrbException {
+        kdcServer.createPrincipals(serverPrincipal);
+        kdcServer.exportPrincipal(serverPrincipal, serviceKeytabFile);
+
+        kdcServer.createPrincipal(clientPrincipal, clientPassword);
+        final TgtTicket tgt = kdcServer.getKrbClient().requestTgt(clientPrincipal, clientPassword);
+        kdcServer.getKrbClient().storeTicket(tgt, ticketCacheFile);
+
+        kdcServer.createPrincipal(clientPrincipal2, clientPassword2);
+        final TgtTicket tgt2 = kdcServer.getKrbClient().requestTgt(clientPrincipal2, clientPassword2);
+        kdcServer.getKrbClient().storeTicket(tgt2, ticketCacheFile2);
+
+        kdcServer.createPrincipal(userPrincipal, userPassword);
+    }
+
+    public void close() {
+        deletePrincipals();
+
+        try {
+            kdcServer.stop();
+        } catch (KrbException krbex) {
+            logger.warn("Tried to stop KdcServer but encountered an exception", krbex);
+        }
+
+        ticketCacheFile.delete();
+        ticketCacheFile2.delete();
+        serviceKeytabFile.delete();
+        testDir.delete();
+    }
+
+    void deletePrincipals() {
+        try {
+            kdcServer.getKadmin().deleteBuiltinPrincipals();
+        } catch (KrbException krbex) {
+            logger.warn("Tried to delete builtin Principals on teardown but failed", krbex);
+        }
+
+        deletePrincipal(serverPrincipal);
+        deletePrincipal(clientPrincipal);
+        deletePrincipal(clientPrincipal2);
+    }
+
+    private void deletePrincipal(final String principalToDelete) {
+        try {
+            kdcServer.deletePrincipal(principalToDelete);
+        } catch (KrbException krbex) {
+            logger.warn(String.format("Tried to delete %s Principals on teardown but failed", principalToDelete), krbex);
+        }
+    }
+
+    public void createPrincipal(final String principal) throws KrbException {
+        kdcServer.createPrincipal(principal);
+    }
+
+    public static void main(final String[] args) throws Exception{
+        final String projectBaseDir = args[0];
+        // The KDC in docker/gremlin-server.sh needs to be exposed to both the container and the host
+        final KdcFixture kdcFixture = new KdcFixture(projectBaseDir, "0.0.0.0");
+        kdcFixture.setUp();
+        logger.info("KDC started with configuration {}/target/kdc/krb5.conf", projectBaseDir);
+        while (true) {
+            Thread.sleep(1000);
+        }
+    }
+}
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/FeatureSupportTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/FeatureSupportTest.java
index 22abde0..8381a76 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/FeatureSupportTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/FeatureSupportTest.java
@@ -51,7 +51,7 @@
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeFalse;
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/GraphConstructionTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/GraphConstructionTest.java
index 8b3e046..576126a 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/GraphConstructionTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/GraphConstructionTest.java
@@ -20,7 +20,7 @@
 
 import org.apache.tinkerpop.gremlin.AbstractGremlinTest;
 import org.apache.tinkerpop.gremlin.structure.util.GraphFactory;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 import org.junit.Test;
 
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/PropertyTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/PropertyTest.java
index 8b443fc..099b3a3 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/PropertyTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/PropertyTest.java
@@ -40,7 +40,9 @@
 
 import static org.apache.tinkerpop.gremlin.structure.Graph.Features.PropertyFeatures.FEATURE_PROPERTIES;
 import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeThat;
 
@@ -141,6 +143,62 @@
                 fail("Removing an edge property that was already removed should not throw an exception");
             }
         }
+
+        @Test
+        @FeatureRequirementSet(FeatureRequirementSet.Package.VERTICES_ONLY)
+        @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_NULL_PROPERTY_VALUES, supported = false)
+        public void shouldNotAllowNullAddVertex() throws Exception {
+            final Vertex v = this.graph.addVertex("name", null);
+            assertThat(v.properties("name").hasNext(), is(false));
+        }
+
+        @Test
+        @FeatureRequirementSet(FeatureRequirementSet.Package.SIMPLE)
+        @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_NULL_PROPERTY_VALUES, supported = false)
+        public void shouldNotAllowNullAddEdge() throws Exception {
+            final Vertex v = this.graph.addVertex();
+            final Edge e = v.addEdge("self", v, "name", null);
+            assertThat(e.properties("name").hasNext(), is(false));
+        }
+
+        @Test
+        @FeatureRequirementSet(FeatureRequirementSet.Package.VERTICES_ONLY)
+        @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_NULL_PROPERTY_VALUES)
+        public void shouldAllowNullAddVertex() throws Exception {
+            final Vertex v = this.graph.addVertex("name", null);
+            assertNull(v.value("name"));
+        }
+
+        @Test
+        @FeatureRequirementSet(FeatureRequirementSet.Package.SIMPLE)
+        @FeatureRequirement(featureClass = Graph.Features.EdgeFeatures.class, feature = Graph.Features.EdgeFeatures.FEATURE_NULL_PROPERTY_VALUES)
+        public void shouldAllowNullAddEdge() throws Exception {
+            final Vertex v = this.graph.addVertex();
+            final Edge e = v.addEdge("self", v, "name", null);
+            assertNull(e.value("name"));
+        }
+
+        @Test
+        @FeatureRequirementSet(FeatureRequirementSet.Package.VERTICES_ONLY)
+        @FeatureRequirement(featureClass = Graph.Features.VertexPropertyFeatures.class, feature = Graph.Features.VertexPropertyFeatures.FEATURE_NULL_PROPERTY_VALUES)
+        @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_META_PROPERTIES)
+        public void shouldAllowNullAddVertexProperty() throws Exception {
+            final Vertex v = this.graph.addVertex("person");
+            final VertexProperty vp = v.property("location", "santa fe", "startTime", 1995, "endTime", null);
+            assertEquals(1995, (int) vp.value("startTime"));
+            assertNull(vp.value("endTime"));
+        }
+
+        @Test
+        @FeatureRequirementSet(FeatureRequirementSet.Package.VERTICES_ONLY)
+        @FeatureRequirement(featureClass = Graph.Features.VertexPropertyFeatures.class, feature = Graph.Features.VertexPropertyFeatures.FEATURE_NULL_PROPERTY_VALUES, supported = false)
+        @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_META_PROPERTIES)
+        public void shouldNotAllowNullAddVertexProperty() throws Exception {
+            final Vertex v = this.graph.addVertex("person");
+            final VertexProperty vp = v.property("location", "santa fe", "startTime", 1995, "endTime", null);
+            assertEquals(1995, (int) vp.value("startTime"));
+            assertThat(vp.properties("endTime").hasNext(), is(false));
+        }
     }
 
     /**
@@ -153,7 +211,6 @@
             "providedKeyValuesMustHaveALegalKeyOnEvenIndices"
     })
     @ExceptionCoverage(exceptionClass = Property.Exceptions.class, methods = {
-            "propertyValueCanNotBeNull",
             "propertyKeyCanNotBeEmpty"
     })
     public static class PropertyValidationOnAddExceptionConsistencyTest extends AbstractGremlinTest {
@@ -164,7 +221,6 @@
                     {"providedKeyValuesMustBeAMultipleOfTwo", new Object[]{"odd", "number", "arguments"}, Element.Exceptions.providedKeyValuesMustBeAMultipleOfTwo()},
                     {"providedKeyValuesMustBeAMultipleOfTwo", new Object[]{"odd"}, Element.Exceptions.providedKeyValuesMustBeAMultipleOfTwo()},
                     {"providedKeyValuesMustHaveALegalKeyOnEvenIndices", new Object[]{"odd", "number", 123, "test"}, Element.Exceptions.providedKeyValuesMustHaveALegalKeyOnEvenIndices()},
-                    {"propertyValueCanNotBeNull", new Object[]{"odd", null}, Property.Exceptions.propertyValueCanNotBeNull()},
                     {"providedKeyValuesMustHaveALegalKeyOnEvenIndices", new Object[]{null, "val"}, Element.Exceptions.providedKeyValuesMustHaveALegalKeyOnEvenIndices()},
                     {"propertyKeyCanNotBeEmpty", new Object[]{"", "val"}, Property.Exceptions.propertyKeyCanNotBeEmpty()}});
         }
@@ -245,13 +301,11 @@
 
 
     /**
-     * Checks that properties added to an {@link Element} are validated in a
-     * consistent way when they are set after {@link Vertex} or {@link Edge} construction by throwing an
-     * appropriate exception.
+     * Checks that properties added to an {@link Element} are validated in a consistent way when they are set after
+     * {@link Vertex} or {@link Edge} construction by throwing an appropriate exception.
      */
     @RunWith(Parameterized.class)
     @ExceptionCoverage(exceptionClass = Property.Exceptions.class, methods = {
-            "propertyValueCanNotBeNull",
             "propertyKeyCanNotBeNull",
             "propertyKeyCanNotBeEmpty",
             "propertyKeyCanNotBeAHiddenKey"
@@ -261,7 +315,6 @@
         @Parameterized.Parameters(name = "expect({0})")
         public static Iterable<Object[]> data() {
             return Arrays.asList(new Object[][]{
-                    {"propertyValueCanNotBeNull", "k", null, Property.Exceptions.propertyValueCanNotBeNull()},
                     {"propertyKeyCanNotBeNull", null, "v", Property.Exceptions.propertyKeyCanNotBeNull()},
                     {"propertyKeyCanNotBeEmpty", "", "v", Property.Exceptions.propertyKeyCanNotBeEmpty()},
                     {"propertyKeyCanNotBeAHiddenKey", Graph.Hidden.hide("systemKey"), "value", Property.Exceptions.propertyKeyCanNotBeAHiddenKey(Graph.Hidden.hide("systemKey"))}});
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/RemoteGraph.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/RemoteGraph.java
index 954118b..0498dc0 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/RemoteGraph.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/RemoteGraph.java
@@ -18,8 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.structure;
 
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.configuration2.builder.fluent.Configurations;
 import org.apache.tinkerpop.gremlin.GraphProvider;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
 import org.apache.tinkerpop.gremlin.process.remote.RemoteConnection;
@@ -79,14 +79,6 @@
         method = "*",
         reason = "RemoteGraph does not support direct Graph.compute() access")
 @Graph.OptOut(
-        test = "org.apache.tinkerpop.gremlin.process.computer.bulkloading.BulkLoaderVertexProgramTest",
-        method = "*",
-        reason = "RemoteGraph does not support direct Graph.compute() access")
-@Graph.OptOut(
-        test = "org.apache.tinkerpop.gremlin.process.computer.bulkdumping.BulkDumperVertexProgramTest",
-        method = "*",
-        reason = "RemoteGraph does not support direct Graph.compute() access")
-@Graph.OptOut(
         test = "org.apache.tinkerpop.gremlin.process.computer.clone.CloneVertexProgramTest",
         method = "*",
         reason = "RemoteGraph does not support direct Graph.compute() access")
@@ -102,6 +94,14 @@
         test = "org.apache.tinkerpop.gremlin.process.traversal.TraversalInterruptionComputerTest",
         method = "*",
         reason = "The interruption model in the test can't guarantee interruption at the right time with RemoteGraph.")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.ComplexTest",
+        method = "classicRecommendation",
+        reason = "Test asserts traversal side-effects which are not supported by remote traversals.")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.GroupTest",
+        method = "g_V_group_byXlabelX_byXbothE_groupXaX_byXlabelX_byXweight_sumX_weight_sumX",
+        reason = "Test asserts traversal side-effects which are not supported by remote traversals.")
 public class RemoteGraph implements Graph {
 
     private final RemoteConnection connection;
@@ -136,7 +136,8 @@
     }
 
     public static RemoteGraph open(final String configFile) throws Exception {
-        return open(new PropertiesConfiguration(configFile));
+        final Configurations configs = new Configurations();
+        return open(configs.properties((configFile)));
     }
 
     /**
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/SerializationTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/SerializationTest.java
index 0f910ab..9612b64 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/SerializationTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/SerializationTest.java
@@ -56,7 +56,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/TransactionTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/TransactionTest.java
index d7a651b..76db416 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/TransactionTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/TransactionTest.java
@@ -22,7 +22,7 @@
 import org.apache.tinkerpop.gremlin.ExceptionCoverage;
 import org.apache.tinkerpop.gremlin.FeatureRequirement;
 import org.apache.tinkerpop.gremlin.FeatureRequirementSet;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 import org.junit.Test;
 
@@ -42,7 +42,7 @@
 import static org.hamcrest.core.Is.is;
 import static org.hamcrest.core.IsInstanceOf.instanceOf;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.fail;
 
 /**
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/VertexPropertyTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/VertexPropertyTest.java
index 04b431d..2bad1a9 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/VertexPropertyTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/VertexPropertyTest.java
@@ -37,7 +37,7 @@
 import static org.hamcrest.collection.IsIterableContainingInOrder.contains;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -111,7 +111,8 @@
         @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_META_PROPERTIES)
         @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_MULTI_PROPERTIES)
         @FeatureRequirement(featureClass = Graph.Features.VertexPropertyFeatures.class, feature = Graph.Features.VertexPropertyFeatures.FEATURE_INTEGER_VALUES)
-        public void shouldHandleListVertexProperties() {
+        @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_NULL_PROPERTY_VALUES, supported = false)
+        public void shouldHandleListVertexPropertiesWithoutNullPropertyValues() {
             final Vertex v = graph.addVertex("name", "marko", "age", 34);
             tryCommit(graph, g -> {
                 assertEquals("marko", v.property("name").value());
@@ -169,6 +170,95 @@
 
                 assertVertexEdgeCounts(graph, 1, 0);
             });
+
+            // null property values are not supported so the value should not be added as set or list cardinality,
+            // but single will remove it
+            assertEquals(VertexProperty.empty(), v.property(VertexProperty.Cardinality.list, "name", null));
+            tryCommit(graph, g -> {
+                assertEquals(3, IteratorUtils.count(v.properties("name")));
+                assertEquals(4, IteratorUtils.count(v.properties()));
+                assertVertexEdgeCounts(graph, 1, 0);
+            });
+            assertEquals(VertexProperty.empty(), v.property(VertexProperty.Cardinality.single, "name", null));
+            tryCommit(graph, g -> {
+                assertEquals(0, IteratorUtils.count(v.properties("name")));
+                assertEquals(1, IteratorUtils.count(v.properties()));
+                assertVertexEdgeCounts(graph, 1, 0);
+            });
+        }
+
+        @Test
+        @FeatureRequirementSet(FeatureRequirementSet.Package.VERTICES_ONLY)
+        @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_META_PROPERTIES)
+        @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_MULTI_PROPERTIES)
+        @FeatureRequirement(featureClass = Graph.Features.VertexPropertyFeatures.class, feature = Graph.Features.VertexPropertyFeatures.FEATURE_INTEGER_VALUES)
+        @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_NULL_PROPERTY_VALUES)
+        public void shouldHandleListVertexPropertiesWithNullPropertyValues() {
+            final Vertex v = graph.addVertex("name", "marko", "age", 34);
+            tryCommit(graph, g -> {
+                assertEquals("marko", v.property("name").value());
+                assertEquals("marko", v.value("name"));
+                assertEquals(34, v.property("age").value());
+                assertEquals(34, v.<Integer>value("age").intValue());
+                assertEquals(1, IteratorUtils.count(v.properties("name")));
+                assertEquals(2, IteratorUtils.count(v.properties()));
+                assertVertexEdgeCounts(graph, 1, 0);
+            });
+
+            final VertexProperty<String> property = v.property(VertexProperty.Cardinality.list, "name", "marko a. rodriguez");
+            tryCommit(graph, g -> assertEquals(v, property.element()));
+
+            try {
+                v.property("name");
+                fail("This should throw a: " + Vertex.Exceptions.multiplePropertiesExistForProvidedKey("name"));
+            } catch (final Exception e) {
+                validateException(Vertex.Exceptions.multiplePropertiesExistForProvidedKey("name"), e);
+            }
+
+            assertTrue(IteratorUtils.list(v.values("name")).contains("marko"));
+            assertTrue(IteratorUtils.list(v.values("name")).contains("marko a. rodriguez"));
+            assertEquals(3, IteratorUtils.count(v.properties()));
+            assertEquals(2, IteratorUtils.count(v.properties("name")));
+            assertVertexEdgeCounts(graph, 1, 0);
+
+            assertEquals(v, v.property(VertexProperty.Cardinality.list, "name", "mrodriguez").element());
+            tryCommit(graph, g -> {
+                assertEquals(3, IteratorUtils.count(v.properties("name")));
+                assertEquals(4, IteratorUtils.count(v.properties()));
+                assertVertexEdgeCounts(graph, 1, 0);
+            });
+
+            v.<String>properties("name").forEachRemaining(meta -> {
+                meta.property("counter", meta.value().length());
+            });
+
+            tryCommit(graph, g -> {
+                v.properties().forEachRemaining(meta -> {
+                    assertEquals(meta.key(), meta.label());
+                    assertTrue(meta.isPresent());
+                    assertEquals(v, meta.element());
+                    if (meta.key().equals("age")) {
+                        assertEquals(meta.value(), 34);
+                        assertEquals(0, IteratorUtils.count(meta.properties()));
+                    }
+                    if (meta.key().equals("name")) {
+                        assertEquals(((String) meta.value()).length(), meta.<Integer>value("counter").intValue());
+                        assertEquals(1, IteratorUtils.count(meta.properties()));
+                        assertEquals(1, meta.keys().size());
+                        assertTrue(meta.keys().contains("counter"));
+                    }
+                });
+
+                assertVertexEdgeCounts(graph, 1, 0);
+            });
+
+            // null property values are supported so the value should be added
+            assertEquals(v, v.property(VertexProperty.Cardinality.list, "name", null).element());
+            tryCommit(graph, g -> {
+                assertEquals(4, IteratorUtils.count(v.properties("name")));
+                assertEquals(5, IteratorUtils.count(v.properties()));
+                assertVertexEdgeCounts(graph, 1, 0);
+            });
         }
 
         @Test
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoCustomTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoCustomTest.java
index f4091e1..cb5f3c8 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoCustomTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoCustomTest.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.structure.io;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.AbstractGremlinTest;
 import org.apache.tinkerpop.gremlin.FeatureRequirement;
 import org.apache.tinkerpop.gremlin.structure.Edge;
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoGraphTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoGraphTest.java
index e882505..b3ef335 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoGraphTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoGraphTest.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.structure.io;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.AbstractGremlinTest;
 import org.apache.tinkerpop.gremlin.FeatureRequirement;
 import org.apache.tinkerpop.gremlin.LoadGraphWith;
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoTest.java
index f4b23f2..59e2ca1 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoTest.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.structure.io;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.AbstractGremlinTest;
 import org.apache.tinkerpop.gremlin.FeatureRequirement;
 import org.apache.tinkerpop.gremlin.LoadGraphWith;
@@ -95,7 +95,7 @@
 import static org.hamcrest.core.StringContains.containsString;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeThat;
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/util/star/StarGraphTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/util/star/StarGraphTest.java
index 47604c3..7d04d38 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/util/star/StarGraphTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/util/star/StarGraphTest.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.structure.util.star;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.AbstractGremlinTest;
 import org.apache.tinkerpop.gremlin.FeatureRequirement;
 import org.apache.tinkerpop.gremlin.LoadGraphWith;
diff --git a/gremlin-test/src/test/java/org/apache/tinkerpop/gremlin/features/FeatureReaderTest.java b/gremlin-test/src/test/java/org/apache/tinkerpop/gremlin/features/FeatureReaderTest.java
new file mode 100644
index 0000000..8d67347
--- /dev/null
+++ b/gremlin-test/src/test/java/org/apache/tinkerpop/gremlin/features/FeatureReaderTest.java
@@ -0,0 +1,42 @@
+/*
+ * 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.features;
+
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.number.OrderingComparison.greaterThan;
+import static org.junit.Assert.assertEquals;
+
+public class FeatureReaderTest {
+
+    @Test
+    public void shouldParseInSameOrder() throws IOException {
+        final String projectRoot = "../";
+        final Map<String,List<String>> gremlins = FeatureReader.parse(projectRoot);
+        assertThat(gremlins.size(), greaterThan(0));
+        assertEquals(gremlins,
+                     FeatureReader.parse(projectRoot));
+
+    }
+}
diff --git a/gremlin-test/src/test/java/org/apache/tinkerpop/gremlin/process/FeatureCoverageTest.java b/gremlin-test/src/test/java/org/apache/tinkerpop/gremlin/process/FeatureCoverageTest.java
index 40f4e53..c09c1fe 100644
--- a/gremlin-test/src/test/java/org/apache/tinkerpop/gremlin/process/FeatureCoverageTest.java
+++ b/gremlin-test/src/test/java/org/apache/tinkerpop/gremlin/process/FeatureCoverageTest.java
@@ -91,9 +91,9 @@
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.core.Is.is;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
 
 /**
  * @author Stephen Mallette (http://stephen.genoprime.com)
diff --git a/gremlin-tools/gremlin-benchmark/README.asciidoc b/gremlin-tools/gremlin-benchmark/README.asciidoc
new file mode 100644
index 0000000..84f8d5f
--- /dev/null
+++ b/gremlin-tools/gremlin-benchmark/README.asciidoc
@@ -0,0 +1,31 @@
+////
+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.
+////
+== Apache TinkerPop Benchmarks
+
+This module is for development and testing only and no convenience binaries are produced for it. The compilation
+of this module requires:
+
+[source,xml]
+----
+<dependency>
+    <groupId>javax.annotation</groupId>
+    <artifactId>javax.annotation-api</artifactId>
+    <scope>provided</scope>
+</dependency>
+----
+
+The source for this project can be found at link:javaee/javax.annotation:https://github.com/javaee/javax.annotation.
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-benchmark/pom.xml b/gremlin-tools/gremlin-benchmark/pom.xml
index e7ddfc0..117c81b 100644
--- a/gremlin-tools/gremlin-benchmark/pom.xml
+++ b/gremlin-tools/gremlin-benchmark/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>gremlin-tools</artifactId>
         <groupId>org.apache.tinkerpop</groupId>
-        <version>3.4.12-SNAPSHOT</version>
+        <version>3.5.1-SNAPSHOT</version>
     </parent>
 
     <artifactId>gremlin-benchmark</artifactId>
@@ -78,7 +78,6 @@
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-log4j12</artifactId>
-            <optional>true</optional>
         </dependency>
         <dependency>
             <groupId>log4j</groupId>
diff --git a/gremlin-tools/gremlin-coverage/pom.xml b/gremlin-tools/gremlin-coverage/pom.xml
index 5d44b25..6dc17cd 100644
--- a/gremlin-tools/gremlin-coverage/pom.xml
+++ b/gremlin-tools/gremlin-coverage/pom.xml
@@ -6,7 +6,7 @@
     <parent>
         <artifactId>gremlin-tools</artifactId>
         <groupId>org.apache.tinkerpop</groupId>
-        <version>3.4.12-SNAPSHOT</version>
+        <version>3.5.1-SNAPSHOT</version>
     </parent>
     <artifactId>gremlin-coverage</artifactId>
     <name>Apache TinkerPop :: Gremlin Coverage</name>
diff --git a/gremlin-tools/gremlin-io-test/pom.xml b/gremlin-tools/gremlin-io-test/pom.xml
index 9621252..3c545e5 100644
--- a/gremlin-tools/gremlin-io-test/pom.xml
+++ b/gremlin-tools/gremlin-io-test/pom.xml
@@ -6,7 +6,7 @@
     <parent>
         <artifactId>gremlin-tools</artifactId>
         <groupId>org.apache.tinkerpop</groupId>
-        <version>3.4.12-SNAPSHOT</version>
+        <version>3.5.1-SNAPSHOT</version>
     </parent>
     <artifactId>gremlin-io-test</artifactId>
     <name>Apache TinkerPop :: Gremlin IO Test</name>
@@ -26,6 +26,25 @@
             <artifactId>commons-io</artifactId>
         </dependency>
         <dependency>
+            <groupId>org.codehaus.groovy</groupId>
+            <artifactId>groovy</artifactId>
+            <version>${groovy.version}</version>
+            <classifier>indy</classifier>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.groovy</groupId>
+            <artifactId>groovy-json</artifactId>
+            <version>${groovy.version}</version>
+            <classifier>indy</classifier>
+            <exclusions>
+                <!-- exclude non-indy type -->
+                <exclusion>
+                    <groupId>org.codehaus.groovy</groupId>
+                    <artifactId>groovy</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-log4j12</artifactId>
             <optional>true</optional>
diff --git a/gremlin-tools/gremlin-io-test/scripts/generate-graphbinary-resources.groovy b/gremlin-tools/gremlin-io-test/scripts/generate-graphbinary-resources.groovy
index bde5660..12ecadd 100644
--- a/gremlin-tools/gremlin-io-test/scripts/generate-graphbinary-resources.groovy
+++ b/gremlin-tools/gremlin-io-test/scripts/generate-graphbinary-resources.groovy
@@ -23,7 +23,7 @@
 import org.apache.tinkerpop.gremlin.tinkergraph.structure.*
 import org.apache.tinkerpop.gremlin.structure.*
 import org.apache.tinkerpop.gremlin.structure.io.*
-import org.apache.commons.configuration.BaseConfiguration
+import org.apache.commons.configuration2.BaseConfiguration
 
 new File("${projectBuildDir}/test-case-data/io/graphbinary").mkdirs()
 
diff --git a/gremlin-tools/gremlin-io-test/scripts/generate-graphson-resources.groovy b/gremlin-tools/gremlin-io-test/scripts/generate-graphson-resources.groovy
index 03112ed..1ea68e1 100644
--- a/gremlin-tools/gremlin-io-test/scripts/generate-graphson-resources.groovy
+++ b/gremlin-tools/gremlin-io-test/scripts/generate-graphson-resources.groovy
@@ -23,7 +23,7 @@
 import org.apache.tinkerpop.gremlin.structure.*
 import org.apache.tinkerpop.gremlin.structure.io.graphson.*
 import org.apache.tinkerpop.gremlin.structure.io.Model
-import org.apache.commons.configuration.BaseConfiguration
+import org.apache.commons.configuration2.BaseConfiguration
 
 new File("${projectBuildDir}/dev-docs/").mkdirs()
 new File("${projectBuildDir}/test-case-data/io/graphson/").mkdirs()
diff --git a/gremlin-tools/gremlin-io-test/scripts/generate-gryo-resources.groovy b/gremlin-tools/gremlin-io-test/scripts/generate-gryo-resources.groovy
index 97d9911..7301b44 100644
--- a/gremlin-tools/gremlin-io-test/scripts/generate-gryo-resources.groovy
+++ b/gremlin-tools/gremlin-io-test/scripts/generate-gryo-resources.groovy
@@ -22,7 +22,7 @@
 import org.apache.tinkerpop.gremlin.structure.*
 import org.apache.tinkerpop.gremlin.structure.io.gryo.*
 import org.apache.tinkerpop.gremlin.structure.io.*
-import org.apache.commons.configuration.BaseConfiguration
+import org.apache.commons.configuration2.BaseConfiguration
 
 new File("${projectBuildDir}/dev-docs/").mkdirs()
 new File("${projectBuildDir}/test-case-data/io/gryo").mkdirs()
diff --git a/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/Model.java b/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/Model.java
index aff0f1a..8959faa 100644
--- a/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/Model.java
+++ b/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/Model.java
@@ -18,8 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.structure.io;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
 import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
@@ -120,6 +120,12 @@
                 .join(Compatibilities.with(GraphSONCompatibility.class).configuredAs(".*no-types|v1d0")
                 .join(Compatibilities.with(GraphSONCompatibility.class).beforeRelease("3.4.0"))).matchToArray();
 
+        // the inverse of this definition is basically 3.5.0 or better for both GraphSON and Gryo with no support for
+        // untyped GraphSON anywhere along the way
+        final Compatibility[] before3_5_0 = Compatibilities.with(GryoCompatibility.class).beforeRelease("3.5.0")
+                .join(Compatibilities.with(GraphSONCompatibility.class).configuredAs(".*no-types|v1d0")
+                        .join(Compatibilities.with(GraphSONCompatibility.class).beforeRelease("3.5.0"))).matchToArray();
+
         // there is no point to testing gryo for list/map/set as they are kryo primitives essentially
         final Compatibility[] noGraphSONBeforeV3AndNoGryo = Compatibilities.with(GraphSONCompatibility.class).configuredAs(".*v2d0-partial|v1d0|v2d0-no-types").join(Compatibilities.GRYO_ONLY).matchToArray();
 
@@ -169,7 +175,7 @@
         addGraphProcessEntry(Column.keys, "Column", "", Compatibilities.UNTYPED_GRAPHSON.matchToArray());
         addGraphProcessEntry(Direction.OUT, "Direction", "", Compatibilities.UNTYPED_GRAPHSON.matchToArray());
         addGraphProcessEntry(Operator.sum, "Operator", "", Compatibilities.UNTYPED_GRAPHSON.matchToArray());
-        addGraphProcessEntry(Order.shuffle, "Order", "", Compatibilities.UNTYPED_GRAPHSON.matchToArray());
+        addGraphProcessEntry(Order.shuffle, "Order", "", before3_5_0);
         addGraphProcessEntry(TraversalOptionParent.Pick.any, "Pick", "", Compatibilities.UNTYPED_GRAPHSON.matchToArray());
         addGraphProcessEntry(Pop.all, "Pop", "", Compatibilities.UNTYPED_GRAPHSON.matchToArray());
         addGraphProcessEntry(org.apache.tinkerpop.gremlin.util.function.Lambda.function("{ it.get() }"), "Lambda", "", Compatibilities.UNTYPED_GRAPHSON.matchToArray());
diff --git a/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphbinary/GraphBinaryCompatibility.java b/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphbinary/GraphBinaryCompatibility.java
index 8630645..6309963 100644
--- a/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphbinary/GraphBinaryCompatibility.java
+++ b/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphbinary/GraphBinaryCompatibility.java
@@ -53,7 +53,9 @@
     V1_3_4_9("3.4.9", "1.0", "v1"),
     V1_3_4_10("3.4.10", "1.0", "v1"),
     V1_3_4_11("3.4.11", "1.0", "v1"),
-    V1_3_4_12("3.4.12", "1.0", "v1");
+    V1_3_4_12("3.4.12", "1.0", "v1"),
+
+    V1_3_5_0("3.5.0", "1.0", "v1");
 
     private static final String SEP = File.separator;
 
diff --git a/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONCompatibility.java b/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONCompatibility.java
index f637e82..8db65a4 100644
--- a/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONCompatibility.java
+++ b/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONCompatibility.java
@@ -151,7 +151,12 @@
     V1D0_3_4_12("3.4.12", "1.0", "v1d0"),
     V2D0_PARTIAL_3_4_12("3.4.12", "2.0", "v2d0-partial"),
     V2D0_NO_TYPE_3_4_12("3.4.12", "2.0", "v2d0-no-types"),
-    V3D0_PARTIAL_3_4_12("3.4.12", "3.0", "v3d0");
+    V3D0_PARTIAL_3_4_12("3.4.12", "3.0", "v3d0"),
+
+    V1D0_3_5_0("3.5.0", "1.0", "v1d0"),
+    V2D0_PARTIAL_3_5_0("3.5.0", "2.0", "v2d0-partial"),
+    V2D0_NO_TYPE_3_5_0("3.5.0", "2.0", "v2d0-no-types"),
+    V3D0_PARTIAL_3_5_0("3.5.0", "3.0", "v3d0");
 
     private static final String SEP = File.separator;
 
diff --git a/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoCompatibility.java b/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoCompatibility.java
index 880518e..3ad99ac 100644
--- a/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoCompatibility.java
+++ b/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoCompatibility.java
@@ -101,7 +101,10 @@
     V1D0_3_4_11("3.4.11", "1.0", "v1d0"),
     V3D0_3_4_11("3.4.11", "3.0", "v3d0"),
     V1D0_3_4_12("3.4.12", "1.0", "v1d0"),
-    V3D0_3_4_12("3.4.12", "3.0", "v3d0");
+    V3D0_3_4_12("3.4.12", "3.0", "v3d0"),
+
+    V1D0_3_5_0("3.5.0", "1.0", "v1d0"),
+    V3D0_3_5_0("3.5.0", "3.0", "v3d0");
 
     private static final String SEP = File.separator;
 
diff --git a/gremlin-tools/gremlin-io-test/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphbinary/GraphBinaryCompatibilityTest.java b/gremlin-tools/gremlin-io-test/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphbinary/GraphBinaryCompatibilityTest.java
index b7922b8..f3e7661 100644
--- a/gremlin-tools/gremlin-io-test/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphbinary/GraphBinaryCompatibilityTest.java
+++ b/gremlin-tools/gremlin-io-test/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphbinary/GraphBinaryCompatibilityTest.java
@@ -56,7 +56,7 @@
                 {GraphBinaryCompatibility.V1_3_4_11, readerV1, writerV1 },
                 {GraphBinaryCompatibility.V1_3_4_12, readerV1, writerV1 },
 
-
+                {GraphBinaryCompatibility.V1_3_5_0, readerV1, writerV1 }
         });
     }
 
diff --git a/gremlin-tools/gremlin-io-test/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypedCompatibilityTest.java b/gremlin-tools/gremlin-io-test/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypedCompatibilityTest.java
index c435983..cf8e80b 100644
--- a/gremlin-tools/gremlin-io-test/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypedCompatibilityTest.java
+++ b/gremlin-tools/gremlin-io-test/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypedCompatibilityTest.java
@@ -109,7 +109,8 @@
                 {GraphSONCompatibility.V2D0_PARTIAL_3_4_12, mapperV2 },
                 {GraphSONCompatibility.V3D0_PARTIAL_3_4_12, mapperV3 },
 
-
+                {GraphSONCompatibility.V2D0_PARTIAL_3_5_0, mapperV2 },
+                {GraphSONCompatibility.V3D0_PARTIAL_3_5_0, mapperV3 }
         });
     }
 
diff --git a/gremlin-tools/gremlin-io-test/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONUntypedCompatibilityTest.java b/gremlin-tools/gremlin-io-test/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONUntypedCompatibilityTest.java
index fcd4860..af0687d 100644
--- a/gremlin-tools/gremlin-io-test/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONUntypedCompatibilityTest.java
+++ b/gremlin-tools/gremlin-io-test/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONUntypedCompatibilityTest.java
@@ -117,7 +117,8 @@
                 {GraphSONCompatibility.V1D0_3_4_12, mapperV1 },
                 {GraphSONCompatibility.V2D0_NO_TYPE_3_4_12, mapperV2 },
 
-
+                {GraphSONCompatibility.V1D0_3_5_0, mapperV1 },
+                {GraphSONCompatibility.V2D0_NO_TYPE_3_5_0, mapperV2 }
         });
     }
 
diff --git a/gremlin-tools/gremlin-io-test/src/test/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoCompatibilityTest.java b/gremlin-tools/gremlin-io-test/src/test/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoCompatibilityTest.java
index 350764b..85c9270 100644
--- a/gremlin-tools/gremlin-io-test/src/test/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoCompatibilityTest.java
+++ b/gremlin-tools/gremlin-io-test/src/test/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoCompatibilityTest.java
@@ -106,7 +106,8 @@
                 {GryoCompatibility.V1D0_3_4_12, mapperV1 },
                 {GryoCompatibility.V3D0_3_4_12, mapperV3 },
 
-
+                {GryoCompatibility.V1D0_3_5_0, mapperV1 },
+                {GryoCompatibility.V3D0_3_5_0, mapperV3 }
         });
     }
 
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/barrier-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/barrier-v1.gbin
new file mode 100644
index 0000000..f905861
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/barrier-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/bigdecimal-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/bigdecimal-v1.gbin
new file mode 100644
index 0000000..921d957
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/bigdecimal-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/biginteger-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/biginteger-v1.gbin
new file mode 100644
index 0000000..d841fbe
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/biginteger-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/binding-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/binding-v1.gbin
new file mode 100644
index 0000000..79620eb
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/binding-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/bulkset-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/bulkset-v1.gbin
new file mode 100644
index 0000000..4542906
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/bulkset-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/byte-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/byte-v1.gbin
new file mode 100644
index 0000000..af9544f
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/byte-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/bytebuffer-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/bytebuffer-v1.gbin
new file mode 100644
index 0000000..39793d2
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/bytebuffer-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/bytecode-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/bytecode-v1.gbin
new file mode 100644
index 0000000..bc76c2e
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/bytecode-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/cardinality-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/cardinality-v1.gbin
new file mode 100644
index 0000000..3c875a5
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/cardinality-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/char-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/char-v1.gbin
new file mode 100644
index 0000000..b9d97e6
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/char-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/class-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/class-v1.gbin
new file mode 100644
index 0000000..6be272d
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/class-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/column-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/column-v1.gbin
new file mode 100644
index 0000000..c6805c8
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/column-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/date-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/date-v1.gbin
new file mode 100644
index 0000000..e68e17a
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/date-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/direction-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/direction-v1.gbin
new file mode 100644
index 0000000..3caaba3
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/direction-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/double-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/double-v1.gbin
new file mode 100644
index 0000000..e538a62
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/double-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/duration-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/duration-v1.gbin
new file mode 100644
index 0000000..7ffa3ad
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/duration-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/edge-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/edge-v1.gbin
new file mode 100644
index 0000000..086e85d
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/edge-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/float-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/float-v1.gbin
new file mode 100644
index 0000000..322772c
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/float-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/inetaddress-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/inetaddress-v1.gbin
new file mode 100644
index 0000000..b613ddb
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/inetaddress-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/instant-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/instant-v1.gbin
new file mode 100644
index 0000000..3335532
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/instant-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/integer-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/integer-v1.gbin
new file mode 100644
index 0000000..7dc246a
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/integer-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/lambda-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/lambda-v1.gbin
new file mode 100644
index 0000000..b0e98f9
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/lambda-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/list-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/list-v1.gbin
new file mode 100644
index 0000000..1aa405d
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/list-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/localdate-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/localdate-v1.gbin
new file mode 100644
index 0000000..2c9e211
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/localdate-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/localdatetime-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/localdatetime-v1.gbin
new file mode 100644
index 0000000..2e0c83c
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/localdatetime-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/localtime-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/localtime-v1.gbin
new file mode 100644
index 0000000..05785c6
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/localtime-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/long-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/long-v1.gbin
new file mode 100644
index 0000000..cee0083
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/long-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/map-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/map-v1.gbin
new file mode 100644
index 0000000..46cd9e2
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/map-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/metrics-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/metrics-v1.gbin
new file mode 100644
index 0000000..dea77a5
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/metrics-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/monthday-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/monthday-v1.gbin
new file mode 100644
index 0000000..c128263
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/monthday-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/offsetdatetime-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/offsetdatetime-v1.gbin
new file mode 100644
index 0000000..4b2aabb
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/offsetdatetime-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/offsettime-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/offsettime-v1.gbin
new file mode 100644
index 0000000..a4c8c5b
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/offsettime-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/operator-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/operator-v1.gbin
new file mode 100644
index 0000000..84717cc
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/operator-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/order-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/order-v1.gbin
new file mode 100644
index 0000000..311b6ad
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/order-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/p-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/p-v1.gbin
new file mode 100644
index 0000000..ac60799
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/p-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/pand-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/pand-v1.gbin
new file mode 100644
index 0000000..3237c94
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/pand-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/path-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/path-v1.gbin
new file mode 100644
index 0000000..ba075ac
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/path-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/period-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/period-v1.gbin
new file mode 100644
index 0000000..f7dab35
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/period-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/pick-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/pick-v1.gbin
new file mode 100644
index 0000000..77aca2f
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/pick-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/pop-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/pop-v1.gbin
new file mode 100644
index 0000000..f698c94
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/pop-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/por-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/por-v1.gbin
new file mode 100644
index 0000000..7c0b3ab
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/por-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/property-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/property-v1.gbin
new file mode 100644
index 0000000..ddc34e5
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/property-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/pwithin-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/pwithin-v1.gbin
new file mode 100644
index 0000000..5ad30a9
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/pwithin-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/pwithout-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/pwithout-v1.gbin
new file mode 100644
index 0000000..5b195db
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/pwithout-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/scope-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/scope-v1.gbin
new file mode 100644
index 0000000..534b956
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/scope-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/set-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/set-v1.gbin
new file mode 100644
index 0000000..02df059
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/set-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/short-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/short-v1.gbin
new file mode 100644
index 0000000..e1d2d7d
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/short-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/t-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/t-v1.gbin
new file mode 100644
index 0000000..a6376db
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/t-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/textp-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/textp-v1.gbin
new file mode 100644
index 0000000..c796468
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/textp-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/timestamp-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/timestamp-v1.gbin
new file mode 100644
index 0000000..4fc4e5e
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/timestamp-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/tinkergraph-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/tinkergraph-v1.gbin
new file mode 100644
index 0000000..a0a76d1
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/tinkergraph-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/traversalmetrics-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/traversalmetrics-v1.gbin
new file mode 100644
index 0000000..c947e62
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/traversalmetrics-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/traverser-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/traverser-v1.gbin
new file mode 100644
index 0000000..8e47cc0
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/traverser-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/uuid-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/uuid-v1.gbin
new file mode 100644
index 0000000..7f1775d
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/uuid-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/vertex-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/vertex-v1.gbin
new file mode 100644
index 0000000..7fb9d65
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/vertex-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/vertexproperty-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/vertexproperty-v1.gbin
new file mode 100644
index 0000000..89f0329
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/vertexproperty-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/year-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/year-v1.gbin
new file mode 100644
index 0000000..1fe0c74
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/year-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/yearmonth-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/yearmonth-v1.gbin
new file mode 100644
index 0000000..481a121
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/yearmonth-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/zoneoffset-v1.gbin b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/zoneoffset-v1.gbin
new file mode 100644
index 0000000..2867c97
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/_3_5_0/zoneoffset-v1.gbin
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/authenticationchallenge-v1d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/authenticationchallenge-v1d0.json
new file mode 100644
index 0000000..8c5b82c
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/authenticationchallenge-v1d0.json
@@ -0,0 +1,12 @@
+{
+  "requestId" : "41d2e28a-20a4-4ab0-b379-d810dede3786",
+  "status" : {
+    "message" : "",
+    "code" : 407,
+    "attributes" : { }
+  },
+  "result" : {
+    "data" : null,
+    "meta" : { }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/authenticationchallenge-v2d0-no-types.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/authenticationchallenge-v2d0-no-types.json
new file mode 100644
index 0000000..8c5b82c
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/authenticationchallenge-v2d0-no-types.json
@@ -0,0 +1,12 @@
+{
+  "requestId" : "41d2e28a-20a4-4ab0-b379-d810dede3786",
+  "status" : {
+    "message" : "",
+    "code" : 407,
+    "attributes" : { }
+  },
+  "result" : {
+    "data" : null,
+    "meta" : { }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/authenticationchallenge-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/authenticationchallenge-v2d0-partial.json
new file mode 100644
index 0000000..8c5b82c
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/authenticationchallenge-v2d0-partial.json
@@ -0,0 +1,12 @@
+{
+  "requestId" : "41d2e28a-20a4-4ab0-b379-d810dede3786",
+  "status" : {
+    "message" : "",
+    "code" : 407,
+    "attributes" : { }
+  },
+  "result" : {
+    "data" : null,
+    "meta" : { }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/authenticationchallenge-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/authenticationchallenge-v3d0.json
new file mode 100644
index 0000000..d1734c6
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/authenticationchallenge-v3d0.json
@@ -0,0 +1,18 @@
+{
+  "requestId" : "41d2e28a-20a4-4ab0-b379-d810dede3786",
+  "status" : {
+    "message" : "",
+    "code" : 407,
+    "attributes" : {
+      "@type" : "g:Map",
+      "@value" : [ ]
+    }
+  },
+  "result" : {
+    "data" : null,
+    "meta" : {
+      "@type" : "g:Map",
+      "@value" : [ ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/authenticationresponse-v1d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/authenticationresponse-v1d0.json
new file mode 100644
index 0000000..838e1fd
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/authenticationresponse-v1d0.json
@@ -0,0 +1,9 @@
+{
+  "requestId" : "cb682578-9d92-4499-9ebc-5c6aa73c5397",
+  "op" : "authentication",
+  "processor" : "",
+  "args" : {
+    "saslMechanism" : "PLAIN",
+    "sasl" : "AHN0ZXBocGhlbgBwYXNzd29yZA=="
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/authenticationresponse-v2d0-no-types.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/authenticationresponse-v2d0-no-types.json
new file mode 100644
index 0000000..838e1fd
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/authenticationresponse-v2d0-no-types.json
@@ -0,0 +1,9 @@
+{
+  "requestId" : "cb682578-9d92-4499-9ebc-5c6aa73c5397",
+  "op" : "authentication",
+  "processor" : "",
+  "args" : {
+    "saslMechanism" : "PLAIN",
+    "sasl" : "AHN0ZXBocGhlbgBwYXNzd29yZA=="
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/authenticationresponse-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/authenticationresponse-v2d0-partial.json
new file mode 100644
index 0000000..838e1fd
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/authenticationresponse-v2d0-partial.json
@@ -0,0 +1,9 @@
+{
+  "requestId" : "cb682578-9d92-4499-9ebc-5c6aa73c5397",
+  "op" : "authentication",
+  "processor" : "",
+  "args" : {
+    "saslMechanism" : "PLAIN",
+    "sasl" : "AHN0ZXBocGhlbgBwYXNzd29yZA=="
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/authenticationresponse-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/authenticationresponse-v3d0.json
new file mode 100644
index 0000000..daceca2
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/authenticationresponse-v3d0.json
@@ -0,0 +1,9 @@
+{
+  "requestId" : "cb682578-9d92-4499-9ebc-5c6aa73c5397",
+  "op" : "authentication",
+  "processor" : "",
+  "args" : {
+    "@type" : "g:Map",
+    "@value" : [ "saslMechanism", "PLAIN", "sasl", "AHN0ZXBocGhlbgBwYXNzd29yZA==" ]
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/barrier-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/barrier-v2d0-partial.json
new file mode 100644
index 0000000..7ddccdd
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/barrier-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:Barrier",
+  "@value" : "normSack"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/barrier-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/barrier-v3d0.json
new file mode 100644
index 0000000..7ddccdd
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/barrier-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:Barrier",
+  "@value" : "normSack"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/bigdecimal-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/bigdecimal-v2d0-partial.json
new file mode 100644
index 0000000..475337c
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/bigdecimal-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:BigDecimal",
+  "@value" : 123456789987654321123456789987654321
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/bigdecimal-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/bigdecimal-v3d0.json
new file mode 100644
index 0000000..475337c
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/bigdecimal-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:BigDecimal",
+  "@value" : 123456789987654321123456789987654321
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/biginteger-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/biginteger-v2d0-partial.json
new file mode 100644
index 0000000..58e6114
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/biginteger-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:BigInteger",
+  "@value" : 123456789987654321123456789987654321
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/biginteger-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/biginteger-v3d0.json
new file mode 100644
index 0000000..58e6114
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/biginteger-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:BigInteger",
+  "@value" : 123456789987654321123456789987654321
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/binding-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/binding-v2d0-partial.json
new file mode 100644
index 0000000..579b8c7
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/binding-v2d0-partial.json
@@ -0,0 +1,10 @@
+{
+  "@type" : "g:Binding",
+  "@value" : {
+    "key" : "x",
+    "value" : {
+      "@type" : "g:Int32",
+      "@value" : 1
+    }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/binding-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/binding-v3d0.json
new file mode 100644
index 0000000..579b8c7
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/binding-v3d0.json
@@ -0,0 +1,10 @@
+{
+  "@type" : "g:Binding",
+  "@value" : {
+    "key" : "x",
+    "value" : {
+      "@type" : "g:Int32",
+      "@value" : 1
+    }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/bulkset-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/bulkset-v2d0-partial.json
new file mode 100644
index 0000000..c844975
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/bulkset-v2d0-partial.json
@@ -0,0 +1 @@
+[ "marko", "josh", "josh" ]
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/bulkset-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/bulkset-v3d0.json
new file mode 100644
index 0000000..c216a36
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/bulkset-v3d0.json
@@ -0,0 +1,10 @@
+{
+  "@type" : "g:BulkSet",
+  "@value" : [ "marko", {
+    "@type" : "g:Int64",
+    "@value" : 1
+  }, "josh", {
+    "@type" : "g:Int64",
+    "@value" : 2
+  } ]
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/byte-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/byte-v2d0-partial.json
new file mode 100644
index 0000000..979625b
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/byte-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:Byte",
+  "@value" : 1
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/byte-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/byte-v3d0.json
new file mode 100644
index 0000000..979625b
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/byte-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:Byte",
+  "@value" : 1
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/bytebuffer-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/bytebuffer-v2d0-partial.json
new file mode 100644
index 0000000..5724115
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/bytebuffer-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:ByteBuffer",
+  "@value" : "c29tZSBieXRlcyBmb3IgeW91"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/bytebuffer-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/bytebuffer-v3d0.json
new file mode 100644
index 0000000..5724115
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/bytebuffer-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:ByteBuffer",
+  "@value" : "c29tZSBieXRlcyBmb3IgeW91"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/bytecode-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/bytecode-v2d0-partial.json
new file mode 100644
index 0000000..269d277
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/bytecode-v2d0-partial.json
@@ -0,0 +1,6 @@
+{
+  "@type" : "g:Bytecode",
+  "@value" : {
+    "step" : [ [ "V" ], [ "hasLabel", "person" ], [ "out" ], [ "in" ], [ "tree" ] ]
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/bytecode-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/bytecode-v3d0.json
new file mode 100644
index 0000000..269d277
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/bytecode-v3d0.json
@@ -0,0 +1,6 @@
+{
+  "@type" : "g:Bytecode",
+  "@value" : {
+    "step" : [ [ "V" ], [ "hasLabel", "person" ], [ "out" ], [ "in" ], [ "tree" ] ]
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/cardinality-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/cardinality-v2d0-partial.json
new file mode 100644
index 0000000..834e64e
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/cardinality-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:Cardinality",
+  "@value" : "list"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/cardinality-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/cardinality-v3d0.json
new file mode 100644
index 0000000..834e64e
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/cardinality-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:Cardinality",
+  "@value" : "list"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/char-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/char-v2d0-partial.json
new file mode 100644
index 0000000..8f27e9d
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/char-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:Char",
+  "@value" : "x"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/char-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/char-v3d0.json
new file mode 100644
index 0000000..8f27e9d
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/char-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:Char",
+  "@value" : "x"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/class-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/class-v2d0-partial.json
new file mode 100644
index 0000000..80f15a2
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/class-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:Class",
+  "@value" : "java.io.File"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/class-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/class-v3d0.json
new file mode 100644
index 0000000..80f15a2
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/class-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:Class",
+  "@value" : "java.io.File"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/column-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/column-v2d0-partial.json
new file mode 100644
index 0000000..0b3a56e
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/column-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:Column",
+  "@value" : "keys"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/column-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/column-v3d0.json
new file mode 100644
index 0000000..0b3a56e
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/column-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:Column",
+  "@value" : "keys"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/date-v2d0-no-types.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/date-v2d0-no-types.json
new file mode 100644
index 0000000..03b71a0
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/date-v2d0-no-types.json
@@ -0,0 +1 @@
+1481750076295
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/date-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/date-v2d0-partial.json
new file mode 100644
index 0000000..cf4007a
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/date-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:Date",
+  "@value" : 1481750076295
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/date-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/date-v3d0.json
new file mode 100644
index 0000000..cf4007a
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/date-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:Date",
+  "@value" : 1481750076295
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/direction-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/direction-v2d0-partial.json
new file mode 100644
index 0000000..78cb7e4
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/direction-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:Direction",
+  "@value" : "OUT"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/direction-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/direction-v3d0.json
new file mode 100644
index 0000000..78cb7e4
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/direction-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:Direction",
+  "@value" : "OUT"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/double-v2d0-no-types.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/double-v2d0-no-types.json
new file mode 100644
index 0000000..e772e62
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/double-v2d0-no-types.json
@@ -0,0 +1 @@
+100.0
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/double-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/double-v2d0-partial.json
new file mode 100644
index 0000000..9ae4964
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/double-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:Double",
+  "@value" : 100.0
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/double-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/double-v3d0.json
new file mode 100644
index 0000000..9ae4964
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/double-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:Double",
+  "@value" : 100.0
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/duration-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/duration-v2d0-partial.json
new file mode 100644
index 0000000..05c0ce9
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/duration-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:Duration",
+  "@value" : "PT120H"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/duration-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/duration-v3d0.json
new file mode 100644
index 0000000..05c0ce9
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/duration-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:Duration",
+  "@value" : "PT120H"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/edge-v1d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/edge-v1d0.json
new file mode 100644
index 0000000..0f7f168
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/edge-v1d0.json
@@ -0,0 +1,12 @@
+{
+  "id" : 13,
+  "label" : "develops",
+  "type" : "edge",
+  "inVLabel" : "software",
+  "outVLabel" : "person",
+  "inV" : 10,
+  "outV" : 1,
+  "properties" : {
+    "since" : 2009
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/edge-v2d0-no-types.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/edge-v2d0-no-types.json
new file mode 100644
index 0000000..a8e73db
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/edge-v2d0-no-types.json
@@ -0,0 +1,14 @@
+{
+  "id" : 13,
+  "label" : "develops",
+  "inVLabel" : "software",
+  "outVLabel" : "person",
+  "inV" : 10,
+  "outV" : 1,
+  "properties" : {
+    "since" : {
+      "key" : "since",
+      "value" : 2009
+    }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/edge-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/edge-v2d0-partial.json
new file mode 100644
index 0000000..ba1c52e
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/edge-v2d0-partial.json
@@ -0,0 +1,32 @@
+{
+  "@type" : "g:Edge",
+  "@value" : {
+    "id" : {
+      "@type" : "g:Int32",
+      "@value" : 13
+    },
+    "label" : "develops",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : {
+      "@type" : "g:Int32",
+      "@value" : 10
+    },
+    "outV" : {
+      "@type" : "g:Int32",
+      "@value" : 1
+    },
+    "properties" : {
+      "since" : {
+        "@type" : "g:Property",
+        "@value" : {
+          "key" : "since",
+          "value" : {
+            "@type" : "g:Int32",
+            "@value" : 2009
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/edge-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/edge-v3d0.json
new file mode 100644
index 0000000..ba1c52e
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/edge-v3d0.json
@@ -0,0 +1,32 @@
+{
+  "@type" : "g:Edge",
+  "@value" : {
+    "id" : {
+      "@type" : "g:Int32",
+      "@value" : 13
+    },
+    "label" : "develops",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : {
+      "@type" : "g:Int32",
+      "@value" : 10
+    },
+    "outV" : {
+      "@type" : "g:Int32",
+      "@value" : 1
+    },
+    "properties" : {
+      "since" : {
+        "@type" : "g:Property",
+        "@value" : {
+          "key" : "since",
+          "value" : {
+            "@type" : "g:Int32",
+            "@value" : 2009
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/float-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/float-v2d0-partial.json
new file mode 100644
index 0000000..7179aaf
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/float-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:Float",
+  "@value" : 100.0
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/float-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/float-v3d0.json
new file mode 100644
index 0000000..7179aaf
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/float-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:Float",
+  "@value" : 100.0
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/inetaddress-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/inetaddress-v2d0-partial.json
new file mode 100644
index 0000000..fba98c0
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/inetaddress-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:InetAddress",
+  "@value" : "localhost"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/inetaddress-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/inetaddress-v3d0.json
new file mode 100644
index 0000000..fba98c0
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/inetaddress-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:InetAddress",
+  "@value" : "localhost"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/instant-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/instant-v2d0-partial.json
new file mode 100644
index 0000000..3749741
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/instant-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:Instant",
+  "@value" : "2016-12-14T16:39:19.349Z"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/instant-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/instant-v3d0.json
new file mode 100644
index 0000000..3749741
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/instant-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:Instant",
+  "@value" : "2016-12-14T16:39:19.349Z"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/integer-v2d0-no-types.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/integer-v2d0-no-types.json
new file mode 100644
index 0000000..105d7d9
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/integer-v2d0-no-types.json
@@ -0,0 +1 @@
+100
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/integer-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/integer-v2d0-partial.json
new file mode 100644
index 0000000..750ce7a
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/integer-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:Int32",
+  "@value" : 100
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/integer-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/integer-v3d0.json
new file mode 100644
index 0000000..750ce7a
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/integer-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:Int32",
+  "@value" : 100
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/lambda-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/lambda-v2d0-partial.json
new file mode 100644
index 0000000..5be179b
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/lambda-v2d0-partial.json
@@ -0,0 +1,8 @@
+{
+  "@type" : "g:Lambda",
+  "@value" : {
+    "script" : "{ it.get() }",
+    "language" : "gremlin-groovy",
+    "arguments" : 1
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/lambda-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/lambda-v3d0.json
new file mode 100644
index 0000000..5be179b
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/lambda-v3d0.json
@@ -0,0 +1,8 @@
+{
+  "@type" : "g:Lambda",
+  "@value" : {
+    "script" : "{ it.get() }",
+    "language" : "gremlin-groovy",
+    "arguments" : 1
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/list-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/list-v3d0.json
new file mode 100644
index 0000000..b714e2d
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/list-v3d0.json
@@ -0,0 +1,7 @@
+{
+  "@type" : "g:List",
+  "@value" : [ {
+    "@type" : "g:Int32",
+    "@value" : 1
+  }, "person", true ]
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/localdate-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/localdate-v2d0-partial.json
new file mode 100644
index 0000000..36fb81d
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/localdate-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:LocalDate",
+  "@value" : "2016-01-01"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/localdate-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/localdate-v3d0.json
new file mode 100644
index 0000000..36fb81d
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/localdate-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:LocalDate",
+  "@value" : "2016-01-01"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/localdatetime-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/localdatetime-v2d0-partial.json
new file mode 100644
index 0000000..2d83668
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/localdatetime-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:LocalDateTime",
+  "@value" : "2016-01-01T12:30"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/localdatetime-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/localdatetime-v3d0.json
new file mode 100644
index 0000000..2d83668
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/localdatetime-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:LocalDateTime",
+  "@value" : "2016-01-01T12:30"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/localtime-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/localtime-v2d0-partial.json
new file mode 100644
index 0000000..eff65a7
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/localtime-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:LocalTime",
+  "@value" : "12:30:45"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/localtime-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/localtime-v3d0.json
new file mode 100644
index 0000000..eff65a7
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/localtime-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:LocalTime",
+  "@value" : "12:30:45"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/long-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/long-v2d0-partial.json
new file mode 100644
index 0000000..84b9a23
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/long-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:Int64",
+  "@value" : 100
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/long-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/long-v3d0.json
new file mode 100644
index 0000000..84b9a23
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/long-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:Int64",
+  "@value" : 100
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/map-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/map-v3d0.json
new file mode 100644
index 0000000..7ad59c9
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/map-v3d0.json
@@ -0,0 +1,25 @@
+{
+  "@type" : "g:Map",
+  "@value" : [ {
+    "@type" : "g:Date",
+    "@value" : 1481750076295
+  }, "red", {
+    "@type" : "g:List",
+    "@value" : [ {
+      "@type" : "g:Int32",
+      "@value" : 1
+    }, {
+      "@type" : "g:Int32",
+      "@value" : 2
+    }, {
+      "@type" : "g:Int32",
+      "@value" : 3
+    } ]
+  }, {
+    "@type" : "g:Date",
+    "@value" : 1481750076295
+  }, "test", {
+    "@type" : "g:Int32",
+    "@value" : 123
+  } ]
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/metrics-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/metrics-v2d0-partial.json
new file mode 100644
index 0000000..7b1e964
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/metrics-v2d0-partial.json
@@ -0,0 +1,54 @@
+{
+  "@type" : "g:Metrics",
+  "@value" : {
+    "dur" : {
+      "@type" : "g:Double",
+      "@value" : 100.0
+    },
+    "counts" : {
+      "traverserCount" : {
+        "@type" : "g:Int64",
+        "@value" : 4
+      },
+      "elementCount" : {
+        "@type" : "g:Int64",
+        "@value" : 4
+      }
+    },
+    "name" : "TinkerGraphStep(vertex,[~label.eq(person)])",
+    "annotations" : {
+      "percentDur" : {
+        "@type" : "g:Double",
+        "@value" : 25.0
+      }
+    },
+    "id" : "7.0.0()",
+    "metrics" : [ {
+      "@type" : "g:Metrics",
+      "@value" : {
+        "dur" : {
+          "@type" : "g:Double",
+          "@value" : 100.0
+        },
+        "counts" : {
+          "traverserCount" : {
+            "@type" : "g:Int64",
+            "@value" : 7
+          },
+          "elementCount" : {
+            "@type" : "g:Int64",
+            "@value" : 7
+          }
+        },
+        "name" : "VertexStep(OUT,vertex)",
+        "annotations" : {
+          "percentDur" : {
+            "@type" : "g:Double",
+            "@value" : 25.0
+          }
+        },
+        "id" : "3.0.0()"
+      }
+    } ]
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/metrics-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/metrics-v3d0.json
new file mode 100644
index 0000000..f6e678b
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/metrics-v3d0.json
@@ -0,0 +1,52 @@
+{
+  "@type" : "g:Metrics",
+  "@value" : {
+    "@type" : "g:Map",
+    "@value" : [ "dur", {
+      "@type" : "g:Double",
+      "@value" : 100.0
+    }, "counts", {
+      "@type" : "g:Map",
+      "@value" : [ "traverserCount", {
+        "@type" : "g:Int64",
+        "@value" : 4
+      }, "elementCount", {
+        "@type" : "g:Int64",
+        "@value" : 4
+      } ]
+    }, "name", "TinkerGraphStep(vertex,[~label.eq(person)])", "annotations", {
+      "@type" : "g:Map",
+      "@value" : [ "percentDur", {
+        "@type" : "g:Double",
+        "@value" : 25.0
+      } ]
+    }, "id", "7.0.0()", "metrics", {
+      "@type" : "g:List",
+      "@value" : [ {
+        "@type" : "g:Metrics",
+        "@value" : {
+          "@type" : "g:Map",
+          "@value" : [ "dur", {
+            "@type" : "g:Double",
+            "@value" : 100.0
+          }, "counts", {
+            "@type" : "g:Map",
+            "@value" : [ "traverserCount", {
+              "@type" : "g:Int64",
+              "@value" : 7
+            }, "elementCount", {
+              "@type" : "g:Int64",
+              "@value" : 7
+            } ]
+          }, "name", "VertexStep(OUT,vertex)", "annotations", {
+            "@type" : "g:Map",
+            "@value" : [ "percentDur", {
+              "@type" : "g:Double",
+              "@value" : 25.0
+            } ]
+          }, "id", "3.0.0()" ]
+        }
+      } ]
+    } ]
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/monthday-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/monthday-v2d0-partial.json
new file mode 100644
index 0000000..5da5914
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/monthday-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:MonthDay",
+  "@value" : "--01-01"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/monthday-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/monthday-v3d0.json
new file mode 100644
index 0000000..5da5914
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/monthday-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:MonthDay",
+  "@value" : "--01-01"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/offsetdatetime-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/offsetdatetime-v2d0-partial.json
new file mode 100644
index 0000000..03f45cd
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/offsetdatetime-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:OffsetDateTime",
+  "@value" : "2007-12-03T10:15:30+01:00"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/offsetdatetime-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/offsetdatetime-v3d0.json
new file mode 100644
index 0000000..03f45cd
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/offsetdatetime-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:OffsetDateTime",
+  "@value" : "2007-12-03T10:15:30+01:00"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/offsettime-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/offsettime-v2d0-partial.json
new file mode 100644
index 0000000..b124953
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/offsettime-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:OffsetTime",
+  "@value" : "10:15:30+01:00"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/offsettime-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/offsettime-v3d0.json
new file mode 100644
index 0000000..b124953
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/offsettime-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:OffsetTime",
+  "@value" : "10:15:30+01:00"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/operator-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/operator-v2d0-partial.json
new file mode 100644
index 0000000..14c1400
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/operator-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:Operator",
+  "@value" : "sum"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/operator-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/operator-v3d0.json
new file mode 100644
index 0000000..14c1400
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/operator-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:Operator",
+  "@value" : "sum"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/order-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/order-v2d0-partial.json
new file mode 100644
index 0000000..4be0432
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/order-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:Order",
+  "@value" : "shuffle"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/order-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/order-v3d0.json
new file mode 100644
index 0000000..4be0432
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/order-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:Order",
+  "@value" : "shuffle"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/p-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/p-v2d0-partial.json
new file mode 100644
index 0000000..5bdfb3b
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/p-v2d0-partial.json
@@ -0,0 +1,10 @@
+{
+  "@type" : "g:P",
+  "@value" : {
+    "predicate" : "gt",
+    "value" : {
+      "@type" : "g:Int32",
+      "@value" : 0
+    }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/p-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/p-v3d0.json
new file mode 100644
index 0000000..5bdfb3b
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/p-v3d0.json
@@ -0,0 +1,10 @@
+{
+  "@type" : "g:P",
+  "@value" : {
+    "predicate" : "gt",
+    "value" : {
+      "@type" : "g:Int32",
+      "@value" : 0
+    }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/pand-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/pand-v2d0-partial.json
new file mode 100644
index 0000000..c271958
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/pand-v2d0-partial.json
@@ -0,0 +1,25 @@
+{
+  "@type" : "g:P",
+  "@value" : {
+    "predicate" : "and",
+    "value" : [ {
+      "@type" : "g:P",
+      "@value" : {
+        "predicate" : "gt",
+        "value" : {
+          "@type" : "g:Int32",
+          "@value" : 0
+        }
+      }
+    }, {
+      "@type" : "g:P",
+      "@value" : {
+        "predicate" : "lt",
+        "value" : {
+          "@type" : "g:Int32",
+          "@value" : 10
+        }
+      }
+    } ]
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/pand-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/pand-v3d0.json
new file mode 100644
index 0000000..c271958
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/pand-v3d0.json
@@ -0,0 +1,25 @@
+{
+  "@type" : "g:P",
+  "@value" : {
+    "predicate" : "and",
+    "value" : [ {
+      "@type" : "g:P",
+      "@value" : {
+        "predicate" : "gt",
+        "value" : {
+          "@type" : "g:Int32",
+          "@value" : 0
+        }
+      }
+    }, {
+      "@type" : "g:P",
+      "@value" : {
+        "predicate" : "lt",
+        "value" : {
+          "@type" : "g:Int32",
+          "@value" : 10
+        }
+      }
+    } ]
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/path-v1d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/path-v1d0.json
new file mode 100644
index 0000000..2eee883
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/path-v1d0.json
@@ -0,0 +1,62 @@
+{
+  "labels" : [ [ ], [ ], [ ] ],
+  "objects" : [ {
+    "id" : 1,
+    "label" : "person",
+    "type" : "vertex",
+    "properties" : {
+      "name" : [ {
+        "id" : 0,
+        "value" : "marko"
+      } ],
+      "location" : [ {
+        "id" : 6,
+        "value" : "san diego",
+        "properties" : {
+          "startTime" : 1997,
+          "endTime" : 2001
+        }
+      }, {
+        "id" : 7,
+        "value" : "santa cruz",
+        "properties" : {
+          "startTime" : 2001,
+          "endTime" : 2004
+        }
+      }, {
+        "id" : 8,
+        "value" : "brussels",
+        "properties" : {
+          "startTime" : 2004,
+          "endTime" : 2005
+        }
+      }, {
+        "id" : 9,
+        "value" : "santa fe",
+        "properties" : {
+          "startTime" : 2005
+        }
+      } ]
+    }
+  }, {
+    "id" : 10,
+    "label" : "software",
+    "type" : "vertex",
+    "properties" : {
+      "name" : [ {
+        "id" : 4,
+        "value" : "gremlin"
+      } ]
+    }
+  }, {
+    "id" : 11,
+    "label" : "software",
+    "type" : "vertex",
+    "properties" : {
+      "name" : [ {
+        "id" : 5,
+        "value" : "tinkergraph"
+      } ]
+    }
+  } ]
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/path-v2d0-no-types.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/path-v2d0-no-types.json
new file mode 100644
index 0000000..a592d2f
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/path-v2d0-no-types.json
@@ -0,0 +1,13 @@
+{
+  "labels" : [ [ ], [ ], [ ] ],
+  "objects" : [ {
+    "id" : 1,
+    "label" : "person"
+  }, {
+    "id" : 10,
+    "label" : "software"
+  }, {
+    "id" : 11,
+    "label" : "software"
+  } ]
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/path-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/path-v2d0-partial.json
new file mode 100644
index 0000000..9ccaa00
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/path-v2d0-partial.json
@@ -0,0 +1,34 @@
+{
+  "@type" : "g:Path",
+  "@value" : {
+    "labels" : [ [ ], [ ], [ ] ],
+    "objects" : [ {
+      "@type" : "g:Vertex",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 1
+        },
+        "label" : "person"
+      }
+    }, {
+      "@type" : "g:Vertex",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 10
+        },
+        "label" : "software"
+      }
+    }, {
+      "@type" : "g:Vertex",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 11
+        },
+        "label" : "software"
+      }
+    } ]
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/path-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/path-v3d0.json
new file mode 100644
index 0000000..216b393
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/path-v3d0.json
@@ -0,0 +1,49 @@
+{
+  "@type" : "g:Path",
+  "@value" : {
+    "labels" : {
+      "@type" : "g:List",
+      "@value" : [ {
+        "@type" : "g:Set",
+        "@value" : [ ]
+      }, {
+        "@type" : "g:Set",
+        "@value" : [ ]
+      }, {
+        "@type" : "g:Set",
+        "@value" : [ ]
+      } ]
+    },
+    "objects" : {
+      "@type" : "g:List",
+      "@value" : [ {
+        "@type" : "g:Vertex",
+        "@value" : {
+          "id" : {
+            "@type" : "g:Int32",
+            "@value" : 1
+          },
+          "label" : "person"
+        }
+      }, {
+        "@type" : "g:Vertex",
+        "@value" : {
+          "id" : {
+            "@type" : "g:Int32",
+            "@value" : 10
+          },
+          "label" : "software"
+        }
+      }, {
+        "@type" : "g:Vertex",
+        "@value" : {
+          "id" : {
+            "@type" : "g:Int32",
+            "@value" : 11
+          },
+          "label" : "software"
+        }
+      } ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/period-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/period-v2d0-partial.json
new file mode 100644
index 0000000..20438a1
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/period-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:Period",
+  "@value" : "P1Y6M15D"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/period-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/period-v3d0.json
new file mode 100644
index 0000000..20438a1
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/period-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:Period",
+  "@value" : "P1Y6M15D"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/pick-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/pick-v2d0-partial.json
new file mode 100644
index 0000000..3ca2f2e
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/pick-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:Pick",
+  "@value" : "any"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/pick-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/pick-v3d0.json
new file mode 100644
index 0000000..3ca2f2e
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/pick-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:Pick",
+  "@value" : "any"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/pop-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/pop-v2d0-partial.json
new file mode 100644
index 0000000..271515f
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/pop-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:Pop",
+  "@value" : "all"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/pop-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/pop-v3d0.json
new file mode 100644
index 0000000..271515f
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/pop-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:Pop",
+  "@value" : "all"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/por-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/por-v2d0-partial.json
new file mode 100644
index 0000000..71fcb7d
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/por-v2d0-partial.json
@@ -0,0 +1,31 @@
+{
+  "@type" : "g:P",
+  "@value" : {
+    "predicate" : "or",
+    "value" : [ {
+      "@type" : "g:P",
+      "@value" : {
+        "predicate" : "gt",
+        "value" : {
+          "@type" : "g:Int32",
+          "@value" : 0
+        }
+      }
+    }, {
+      "@type" : "g:P",
+      "@value" : {
+        "predicate" : "within",
+        "value" : [ {
+          "@type" : "g:Int32",
+          "@value" : -1
+        }, {
+          "@type" : "g:Int32",
+          "@value" : -10
+        }, {
+          "@type" : "g:Int32",
+          "@value" : -100
+        } ]
+      }
+    } ]
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/por-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/por-v3d0.json
new file mode 100644
index 0000000..a71b1cf
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/por-v3d0.json
@@ -0,0 +1,34 @@
+{
+  "@type" : "g:P",
+  "@value" : {
+    "predicate" : "or",
+    "value" : [ {
+      "@type" : "g:P",
+      "@value" : {
+        "predicate" : "gt",
+        "value" : {
+          "@type" : "g:Int32",
+          "@value" : 0
+        }
+      }
+    }, {
+      "@type" : "g:P",
+      "@value" : {
+        "predicate" : "within",
+        "value" : {
+          "@type" : "g:List",
+          "@value" : [ {
+            "@type" : "g:Int32",
+            "@value" : -1
+          }, {
+            "@type" : "g:Int32",
+            "@value" : -10
+          }, {
+            "@type" : "g:Int32",
+            "@value" : -100
+          } ]
+        }
+      }
+    } ]
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/property-v1d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/property-v1d0.json
new file mode 100644
index 0000000..c051c0a
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/property-v1d0.json
@@ -0,0 +1,4 @@
+{
+  "key" : "since",
+  "value" : 2009
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/property-v2d0-no-types.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/property-v2d0-no-types.json
new file mode 100644
index 0000000..c051c0a
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/property-v2d0-no-types.json
@@ -0,0 +1,4 @@
+{
+  "key" : "since",
+  "value" : 2009
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/property-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/property-v2d0-partial.json
new file mode 100644
index 0000000..296fe32
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/property-v2d0-partial.json
@@ -0,0 +1,10 @@
+{
+  "@type" : "g:Property",
+  "@value" : {
+    "key" : "since",
+    "value" : {
+      "@type" : "g:Int32",
+      "@value" : 2009
+    }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/property-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/property-v3d0.json
new file mode 100644
index 0000000..296fe32
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/property-v3d0.json
@@ -0,0 +1,10 @@
+{
+  "@type" : "g:Property",
+  "@value" : {
+    "key" : "since",
+    "value" : {
+      "@type" : "g:Int32",
+      "@value" : 2009
+    }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/pwithin-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/pwithin-v2d0-partial.json
new file mode 100644
index 0000000..afa3826
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/pwithin-v2d0-partial.json
@@ -0,0 +1,10 @@
+{
+  "@type" : "g:P",
+  "@value" : {
+    "predicate" : "within",
+    "value" : [ {
+      "@type" : "g:Int32",
+      "@value" : 1
+    } ]
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/pwithin-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/pwithin-v3d0.json
new file mode 100644
index 0000000..83f99cc
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/pwithin-v3d0.json
@@ -0,0 +1,13 @@
+{
+  "@type" : "g:P",
+  "@value" : {
+    "predicate" : "within",
+    "value" : {
+      "@type" : "g:List",
+      "@value" : [ {
+        "@type" : "g:Int32",
+        "@value" : 1
+      } ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/pwithout-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/pwithout-v2d0-partial.json
new file mode 100644
index 0000000..8c2291b
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/pwithout-v2d0-partial.json
@@ -0,0 +1,13 @@
+{
+  "@type" : "g:P",
+  "@value" : {
+    "predicate" : "without",
+    "value" : [ {
+      "@type" : "g:Int32",
+      "@value" : 1
+    }, {
+      "@type" : "g:Int32",
+      "@value" : 2
+    } ]
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/pwithout-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/pwithout-v3d0.json
new file mode 100644
index 0000000..9a16890
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/pwithout-v3d0.json
@@ -0,0 +1,16 @@
+{
+  "@type" : "g:P",
+  "@value" : {
+    "predicate" : "without",
+    "value" : {
+      "@type" : "g:List",
+      "@value" : [ {
+        "@type" : "g:Int32",
+        "@value" : 1
+      }, {
+        "@type" : "g:Int32",
+        "@value" : 2
+      } ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/scope-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/scope-v2d0-partial.json
new file mode 100644
index 0000000..4a74af0
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/scope-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:Scope",
+  "@value" : "local"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/scope-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/scope-v3d0.json
new file mode 100644
index 0000000..4a74af0
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/scope-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:Scope",
+  "@value" : "local"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionclose-v1d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionclose-v1d0.json
new file mode 100644
index 0000000..ac825e8
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionclose-v1d0.json
@@ -0,0 +1,8 @@
+{
+  "requestId" : "cb682578-9d92-4499-9ebc-5c6aa73c5397",
+  "op" : "close",
+  "processor" : "session",
+  "args" : {
+    "session" : "unique-session-identifier"
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionclose-v2d0-no-types.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionclose-v2d0-no-types.json
new file mode 100644
index 0000000..ac825e8
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionclose-v2d0-no-types.json
@@ -0,0 +1,8 @@
+{
+  "requestId" : "cb682578-9d92-4499-9ebc-5c6aa73c5397",
+  "op" : "close",
+  "processor" : "session",
+  "args" : {
+    "session" : "unique-session-identifier"
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionclose-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionclose-v2d0-partial.json
new file mode 100644
index 0000000..ac825e8
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionclose-v2d0-partial.json
@@ -0,0 +1,8 @@
+{
+  "requestId" : "cb682578-9d92-4499-9ebc-5c6aa73c5397",
+  "op" : "close",
+  "processor" : "session",
+  "args" : {
+    "session" : "unique-session-identifier"
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionclose-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionclose-v3d0.json
new file mode 100644
index 0000000..4be1ccd
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionclose-v3d0.json
@@ -0,0 +1,9 @@
+{
+  "requestId" : "cb682578-9d92-4499-9ebc-5c6aa73c5397",
+  "op" : "close",
+  "processor" : "session",
+  "args" : {
+    "@type" : "g:Map",
+    "@value" : [ "session", "unique-session-identifier" ]
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessioneval-v1d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessioneval-v1d0.json
new file mode 100644
index 0000000..8bce82f
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessioneval-v1d0.json
@@ -0,0 +1,13 @@
+{
+  "requestId" : "cb682578-9d92-4499-9ebc-5c6aa73c5397",
+  "op" : "eval",
+  "processor" : "session",
+  "args" : {
+    "gremlin" : "g.V(x)",
+    "language" : "gremlin-groovy",
+    "session" : "unique-session-identifier",
+    "bindings" : {
+      "x" : 1
+    }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessioneval-v2d0-no-types.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessioneval-v2d0-no-types.json
new file mode 100644
index 0000000..8bce82f
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessioneval-v2d0-no-types.json
@@ -0,0 +1,13 @@
+{
+  "requestId" : "cb682578-9d92-4499-9ebc-5c6aa73c5397",
+  "op" : "eval",
+  "processor" : "session",
+  "args" : {
+    "gremlin" : "g.V(x)",
+    "language" : "gremlin-groovy",
+    "session" : "unique-session-identifier",
+    "bindings" : {
+      "x" : 1
+    }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessioneval-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessioneval-v2d0-partial.json
new file mode 100644
index 0000000..8ff8b96
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessioneval-v2d0-partial.json
@@ -0,0 +1,16 @@
+{
+  "requestId" : "cb682578-9d92-4499-9ebc-5c6aa73c5397",
+  "op" : "eval",
+  "processor" : "session",
+  "args" : {
+    "gremlin" : "g.V(x)",
+    "language" : "gremlin-groovy",
+    "session" : "unique-session-identifier",
+    "bindings" : {
+      "x" : {
+        "@type" : "g:Int32",
+        "@value" : 1
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessioneval-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessioneval-v3d0.json
new file mode 100644
index 0000000..301c393
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessioneval-v3d0.json
@@ -0,0 +1,15 @@
+{
+  "requestId" : "cb682578-9d92-4499-9ebc-5c6aa73c5397",
+  "op" : "eval",
+  "processor" : "session",
+  "args" : {
+    "@type" : "g:Map",
+    "@value" : [ "gremlin", "g.V(x)", "language", "gremlin-groovy", "session", "unique-session-identifier", "bindings", {
+      "@type" : "g:Map",
+      "@value" : [ "x", {
+        "@type" : "g:Int32",
+        "@value" : 1
+      } ]
+    } ]
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionevalaliased-v1d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionevalaliased-v1d0.json
new file mode 100644
index 0000000..5f4ef46
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionevalaliased-v1d0.json
@@ -0,0 +1,16 @@
+{
+  "requestId" : "cb682578-9d92-4499-9ebc-5c6aa73c5397",
+  "op" : "eval",
+  "processor" : "session",
+  "args" : {
+    "gremlin" : "social.V(x)",
+    "language" : "gremlin-groovy",
+    "aliases" : {
+      "g" : "social"
+    },
+    "session" : "unique-session-identifier",
+    "bindings" : {
+      "x" : 1
+    }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionevalaliased-v2d0-no-types.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionevalaliased-v2d0-no-types.json
new file mode 100644
index 0000000..5f4ef46
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionevalaliased-v2d0-no-types.json
@@ -0,0 +1,16 @@
+{
+  "requestId" : "cb682578-9d92-4499-9ebc-5c6aa73c5397",
+  "op" : "eval",
+  "processor" : "session",
+  "args" : {
+    "gremlin" : "social.V(x)",
+    "language" : "gremlin-groovy",
+    "aliases" : {
+      "g" : "social"
+    },
+    "session" : "unique-session-identifier",
+    "bindings" : {
+      "x" : 1
+    }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionevalaliased-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionevalaliased-v2d0-partial.json
new file mode 100644
index 0000000..394e5d3
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionevalaliased-v2d0-partial.json
@@ -0,0 +1,19 @@
+{
+  "requestId" : "cb682578-9d92-4499-9ebc-5c6aa73c5397",
+  "op" : "eval",
+  "processor" : "session",
+  "args" : {
+    "gremlin" : "social.V(x)",
+    "language" : "gremlin-groovy",
+    "aliases" : {
+      "g" : "social"
+    },
+    "session" : "unique-session-identifier",
+    "bindings" : {
+      "x" : {
+        "@type" : "g:Int32",
+        "@value" : 1
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionevalaliased-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionevalaliased-v3d0.json
new file mode 100644
index 0000000..7448160
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionevalaliased-v3d0.json
@@ -0,0 +1,18 @@
+{
+  "requestId" : "cb682578-9d92-4499-9ebc-5c6aa73c5397",
+  "op" : "eval",
+  "processor" : "session",
+  "args" : {
+    "@type" : "g:Map",
+    "@value" : [ "gremlin", "social.V(x)", "language", "gremlin-groovy", "aliases", {
+      "@type" : "g:Map",
+      "@value" : [ "g", "social" ]
+    }, "session", "unique-session-identifier", "bindings", {
+      "@type" : "g:Map",
+      "@value" : [ "x", {
+        "@type" : "g:Int32",
+        "@value" : 1
+      } ]
+    } ]
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionlesseval-v1d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionlesseval-v1d0.json
new file mode 100644
index 0000000..8c9a807
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionlesseval-v1d0.json
@@ -0,0 +1,12 @@
+{
+  "requestId" : "cb682578-9d92-4499-9ebc-5c6aa73c5397",
+  "op" : "eval",
+  "processor" : "",
+  "args" : {
+    "gremlin" : "g.V(x)",
+    "language" : "gremlin-groovy",
+    "bindings" : {
+      "x" : 1
+    }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionlesseval-v2d0-no-types.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionlesseval-v2d0-no-types.json
new file mode 100644
index 0000000..8c9a807
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionlesseval-v2d0-no-types.json
@@ -0,0 +1,12 @@
+{
+  "requestId" : "cb682578-9d92-4499-9ebc-5c6aa73c5397",
+  "op" : "eval",
+  "processor" : "",
+  "args" : {
+    "gremlin" : "g.V(x)",
+    "language" : "gremlin-groovy",
+    "bindings" : {
+      "x" : 1
+    }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionlesseval-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionlesseval-v2d0-partial.json
new file mode 100644
index 0000000..81e2f6c
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionlesseval-v2d0-partial.json
@@ -0,0 +1,15 @@
+{
+  "requestId" : "cb682578-9d92-4499-9ebc-5c6aa73c5397",
+  "op" : "eval",
+  "processor" : "",
+  "args" : {
+    "gremlin" : "g.V(x)",
+    "language" : "gremlin-groovy",
+    "bindings" : {
+      "x" : {
+        "@type" : "g:Int32",
+        "@value" : 1
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionlesseval-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionlesseval-v3d0.json
new file mode 100644
index 0000000..dc8c8e6
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionlesseval-v3d0.json
@@ -0,0 +1,15 @@
+{
+  "requestId" : "cb682578-9d92-4499-9ebc-5c6aa73c5397",
+  "op" : "eval",
+  "processor" : "",
+  "args" : {
+    "@type" : "g:Map",
+    "@value" : [ "gremlin", "g.V(x)", "language", "gremlin-groovy", "bindings", {
+      "@type" : "g:Map",
+      "@value" : [ "x", {
+        "@type" : "g:Int32",
+        "@value" : 1
+      } ]
+    } ]
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionlessevalaliased-v1d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionlessevalaliased-v1d0.json
new file mode 100644
index 0000000..59f0c6c
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionlessevalaliased-v1d0.json
@@ -0,0 +1,15 @@
+{
+  "requestId" : "cb682578-9d92-4499-9ebc-5c6aa73c5397",
+  "op" : "eval",
+  "processor" : "",
+  "args" : {
+    "gremlin" : "social.V(x)",
+    "language" : "gremlin-groovy",
+    "aliases" : {
+      "g" : "social"
+    },
+    "bindings" : {
+      "x" : 1
+    }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionlessevalaliased-v2d0-no-types.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionlessevalaliased-v2d0-no-types.json
new file mode 100644
index 0000000..59f0c6c
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionlessevalaliased-v2d0-no-types.json
@@ -0,0 +1,15 @@
+{
+  "requestId" : "cb682578-9d92-4499-9ebc-5c6aa73c5397",
+  "op" : "eval",
+  "processor" : "",
+  "args" : {
+    "gremlin" : "social.V(x)",
+    "language" : "gremlin-groovy",
+    "aliases" : {
+      "g" : "social"
+    },
+    "bindings" : {
+      "x" : 1
+    }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionlessevalaliased-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionlessevalaliased-v2d0-partial.json
new file mode 100644
index 0000000..0f6a54e
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionlessevalaliased-v2d0-partial.json
@@ -0,0 +1,18 @@
+{
+  "requestId" : "cb682578-9d92-4499-9ebc-5c6aa73c5397",
+  "op" : "eval",
+  "processor" : "",
+  "args" : {
+    "gremlin" : "social.V(x)",
+    "language" : "gremlin-groovy",
+    "aliases" : {
+      "g" : "social"
+    },
+    "bindings" : {
+      "x" : {
+        "@type" : "g:Int32",
+        "@value" : 1
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionlessevalaliased-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionlessevalaliased-v3d0.json
new file mode 100644
index 0000000..fc03a37
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/sessionlessevalaliased-v3d0.json
@@ -0,0 +1,18 @@
+{
+  "requestId" : "cb682578-9d92-4499-9ebc-5c6aa73c5397",
+  "op" : "eval",
+  "processor" : "",
+  "args" : {
+    "@type" : "g:Map",
+    "@value" : [ "gremlin", "social.V(x)", "language", "gremlin-groovy", "aliases", {
+      "@type" : "g:Map",
+      "@value" : [ "g", "social" ]
+    }, "bindings", {
+      "@type" : "g:Map",
+      "@value" : [ "x", {
+        "@type" : "g:Int32",
+        "@value" : 1
+      } ]
+    } ]
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/set-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/set-v3d0.json
new file mode 100644
index 0000000..32deea2
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/set-v3d0.json
@@ -0,0 +1,7 @@
+{
+  "@type" : "g:Set",
+  "@value" : [ {
+    "@type" : "g:Int32",
+    "@value" : 1
+  }, "person", true ]
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/short-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/short-v2d0-partial.json
new file mode 100644
index 0000000..c68f5cd
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/short-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:Int16",
+  "@value" : 100
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/short-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/short-v3d0.json
new file mode 100644
index 0000000..c68f5cd
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/short-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:Int16",
+  "@value" : 100
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/standardresult-v1d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/standardresult-v1d0.json
new file mode 100644
index 0000000..9b93727
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/standardresult-v1d0.json
@@ -0,0 +1,50 @@
+{
+  "requestId" : "41d2e28a-20a4-4ab0-b379-d810dede3786",
+  "status" : {
+    "message" : "",
+    "code" : 200,
+    "attributes" : { }
+  },
+  "result" : {
+    "data" : [ {
+      "id" : 1,
+      "label" : "person",
+      "type" : "vertex",
+      "properties" : {
+        "name" : [ {
+          "id" : 0,
+          "value" : "marko"
+        } ],
+        "location" : [ {
+          "id" : 6,
+          "value" : "san diego",
+          "properties" : {
+            "startTime" : 1997,
+            "endTime" : 2001
+          }
+        }, {
+          "id" : 7,
+          "value" : "santa cruz",
+          "properties" : {
+            "startTime" : 2001,
+            "endTime" : 2004
+          }
+        }, {
+          "id" : 8,
+          "value" : "brussels",
+          "properties" : {
+            "startTime" : 2004,
+            "endTime" : 2005
+          }
+        }, {
+          "id" : 9,
+          "value" : "santa fe",
+          "properties" : {
+            "startTime" : 2005
+          }
+        } ]
+      }
+    } ],
+    "meta" : { }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/standardresult-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/standardresult-v2d0-partial.json
new file mode 100644
index 0000000..857c6db
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/standardresult-v2d0-partial.json
@@ -0,0 +1,111 @@
+{
+  "requestId" : "41d2e28a-20a4-4ab0-b379-d810dede3786",
+  "status" : {
+    "message" : "",
+    "code" : 200,
+    "attributes" : { }
+  },
+  "result" : {
+    "data" : [ {
+      "@type" : "g:Vertex",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 1
+        },
+        "label" : "person",
+        "properties" : {
+          "name" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 0
+              },
+              "value" : "marko",
+              "label" : "name"
+            }
+          } ],
+          "location" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 6
+              },
+              "value" : "san diego",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 1997
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2001
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 7
+              },
+              "value" : "santa cruz",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2001
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2004
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 8
+              },
+              "value" : "brussels",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2004
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2005
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 9
+              },
+              "value" : "santa fe",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2005
+                }
+              }
+            }
+          } ]
+        }
+      }
+    } ],
+    "meta" : { }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/standardresult-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/standardresult-v3d0.json
new file mode 100644
index 0000000..dfca400
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/standardresult-v3d0.json
@@ -0,0 +1,120 @@
+{
+  "requestId" : "41d2e28a-20a4-4ab0-b379-d810dede3786",
+  "status" : {
+    "message" : "",
+    "code" : 200,
+    "attributes" : {
+      "@type" : "g:Map",
+      "@value" : [ ]
+    }
+  },
+  "result" : {
+    "data" : {
+      "@type" : "g:List",
+      "@value" : [ {
+        "@type" : "g:Vertex",
+        "@value" : {
+          "id" : {
+            "@type" : "g:Int32",
+            "@value" : 1
+          },
+          "label" : "person",
+          "properties" : {
+            "name" : [ {
+              "@type" : "g:VertexProperty",
+              "@value" : {
+                "id" : {
+                  "@type" : "g:Int64",
+                  "@value" : 0
+                },
+                "value" : "marko",
+                "label" : "name"
+              }
+            } ],
+            "location" : [ {
+              "@type" : "g:VertexProperty",
+              "@value" : {
+                "id" : {
+                  "@type" : "g:Int64",
+                  "@value" : 6
+                },
+                "value" : "san diego",
+                "label" : "location",
+                "properties" : {
+                  "startTime" : {
+                    "@type" : "g:Int32",
+                    "@value" : 1997
+                  },
+                  "endTime" : {
+                    "@type" : "g:Int32",
+                    "@value" : 2001
+                  }
+                }
+              }
+            }, {
+              "@type" : "g:VertexProperty",
+              "@value" : {
+                "id" : {
+                  "@type" : "g:Int64",
+                  "@value" : 7
+                },
+                "value" : "santa cruz",
+                "label" : "location",
+                "properties" : {
+                  "startTime" : {
+                    "@type" : "g:Int32",
+                    "@value" : 2001
+                  },
+                  "endTime" : {
+                    "@type" : "g:Int32",
+                    "@value" : 2004
+                  }
+                }
+              }
+            }, {
+              "@type" : "g:VertexProperty",
+              "@value" : {
+                "id" : {
+                  "@type" : "g:Int64",
+                  "@value" : 8
+                },
+                "value" : "brussels",
+                "label" : "location",
+                "properties" : {
+                  "startTime" : {
+                    "@type" : "g:Int32",
+                    "@value" : 2004
+                  },
+                  "endTime" : {
+                    "@type" : "g:Int32",
+                    "@value" : 2005
+                  }
+                }
+              }
+            }, {
+              "@type" : "g:VertexProperty",
+              "@value" : {
+                "id" : {
+                  "@type" : "g:Int64",
+                  "@value" : 9
+                },
+                "value" : "santa fe",
+                "label" : "location",
+                "properties" : {
+                  "startTime" : {
+                    "@type" : "g:Int32",
+                    "@value" : 2005
+                  }
+                }
+              }
+            } ]
+          }
+        }
+      } ]
+    },
+    "meta" : {
+      "@type" : "g:Map",
+      "@value" : [ ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/t-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/t-v2d0-partial.json
new file mode 100644
index 0000000..9693983
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/t-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:T",
+  "@value" : "label"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/t-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/t-v3d0.json
new file mode 100644
index 0000000..9693983
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/t-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:T",
+  "@value" : "label"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/textp-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/textp-v2d0-partial.json
new file mode 100644
index 0000000..2820989
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/textp-v2d0-partial.json
@@ -0,0 +1,7 @@
+{
+  "@type" : "g:TextP",
+  "@value" : {
+    "predicate" : "containing",
+    "value" : "ark"
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/textp-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/textp-v3d0.json
new file mode 100644
index 0000000..2820989
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/textp-v3d0.json
@@ -0,0 +1,7 @@
+{
+  "@type" : "g:TextP",
+  "@value" : {
+    "predicate" : "containing",
+    "value" : "ark"
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/timestamp-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/timestamp-v2d0-partial.json
new file mode 100644
index 0000000..1ca0e17
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/timestamp-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:Timestamp",
+  "@value" : 1481750076295
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/timestamp-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/timestamp-v3d0.json
new file mode 100644
index 0000000..1ca0e17
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/timestamp-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:Timestamp",
+  "@value" : 1481750076295
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/tinkergraph-v1d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/tinkergraph-v1d0.json
new file mode 100644
index 0000000..13719f6
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/tinkergraph-v1d0.json
@@ -0,0 +1,313 @@
+{
+  "vertices" : [ {
+    "id" : 1,
+    "label" : "person",
+    "type" : "vertex",
+    "properties" : {
+      "name" : [ {
+        "id" : 0,
+        "value" : "marko"
+      } ],
+      "location" : [ {
+        "id" : 6,
+        "value" : "san diego",
+        "properties" : {
+          "startTime" : 1997,
+          "endTime" : 2001
+        }
+      }, {
+        "id" : 7,
+        "value" : "santa cruz",
+        "properties" : {
+          "startTime" : 2001,
+          "endTime" : 2004
+        }
+      }, {
+        "id" : 8,
+        "value" : "brussels",
+        "properties" : {
+          "startTime" : 2004,
+          "endTime" : 2005
+        }
+      }, {
+        "id" : 9,
+        "value" : "santa fe",
+        "properties" : {
+          "startTime" : 2005
+        }
+      } ]
+    }
+  }, {
+    "id" : 7,
+    "label" : "person",
+    "type" : "vertex",
+    "properties" : {
+      "name" : [ {
+        "id" : 1,
+        "value" : "stephen"
+      } ],
+      "location" : [ {
+        "id" : 10,
+        "value" : "centreville",
+        "properties" : {
+          "startTime" : 1990,
+          "endTime" : 2000
+        }
+      }, {
+        "id" : 11,
+        "value" : "dulles",
+        "properties" : {
+          "startTime" : 2000,
+          "endTime" : 2006
+        }
+      }, {
+        "id" : 12,
+        "value" : "purcellville",
+        "properties" : {
+          "startTime" : 2006
+        }
+      } ]
+    }
+  }, {
+    "id" : 8,
+    "label" : "person",
+    "type" : "vertex",
+    "properties" : {
+      "name" : [ {
+        "id" : 2,
+        "value" : "matthias"
+      } ],
+      "location" : [ {
+        "id" : 13,
+        "value" : "bremen",
+        "properties" : {
+          "startTime" : 2004,
+          "endTime" : 2007
+        }
+      }, {
+        "id" : 14,
+        "value" : "baltimore",
+        "properties" : {
+          "startTime" : 2007,
+          "endTime" : 2011
+        }
+      }, {
+        "id" : 15,
+        "value" : "oakland",
+        "properties" : {
+          "startTime" : 2011,
+          "endTime" : 2014
+        }
+      }, {
+        "id" : 16,
+        "value" : "seattle",
+        "properties" : {
+          "startTime" : 2014
+        }
+      } ]
+    }
+  }, {
+    "id" : 9,
+    "label" : "person",
+    "type" : "vertex",
+    "properties" : {
+      "name" : [ {
+        "id" : 3,
+        "value" : "daniel"
+      } ],
+      "location" : [ {
+        "id" : 17,
+        "value" : "spremberg",
+        "properties" : {
+          "startTime" : 1982,
+          "endTime" : 2005
+        }
+      }, {
+        "id" : 18,
+        "value" : "kaiserslautern",
+        "properties" : {
+          "startTime" : 2005,
+          "endTime" : 2009
+        }
+      }, {
+        "id" : 19,
+        "value" : "aachen",
+        "properties" : {
+          "startTime" : 2009
+        }
+      } ]
+    }
+  }, {
+    "id" : 10,
+    "label" : "software",
+    "type" : "vertex",
+    "properties" : {
+      "name" : [ {
+        "id" : 4,
+        "value" : "gremlin"
+      } ]
+    }
+  }, {
+    "id" : 11,
+    "label" : "software",
+    "type" : "vertex",
+    "properties" : {
+      "name" : [ {
+        "id" : 5,
+        "value" : "tinkergraph"
+      } ]
+    }
+  } ],
+  "edges" : [ {
+    "id" : 13,
+    "label" : "develops",
+    "type" : "edge",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 10,
+    "outV" : 1,
+    "properties" : {
+      "since" : 2009
+    }
+  }, {
+    "id" : 14,
+    "label" : "develops",
+    "type" : "edge",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 11,
+    "outV" : 1,
+    "properties" : {
+      "since" : 2010
+    }
+  }, {
+    "id" : 15,
+    "label" : "uses",
+    "type" : "edge",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 10,
+    "outV" : 1,
+    "properties" : {
+      "skill" : 4
+    }
+  }, {
+    "id" : 16,
+    "label" : "uses",
+    "type" : "edge",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 11,
+    "outV" : 1,
+    "properties" : {
+      "skill" : 5
+    }
+  }, {
+    "id" : 17,
+    "label" : "develops",
+    "type" : "edge",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 10,
+    "outV" : 7,
+    "properties" : {
+      "since" : 2010
+    }
+  }, {
+    "id" : 18,
+    "label" : "develops",
+    "type" : "edge",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 11,
+    "outV" : 7,
+    "properties" : {
+      "since" : 2011
+    }
+  }, {
+    "id" : 19,
+    "label" : "uses",
+    "type" : "edge",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 10,
+    "outV" : 7,
+    "properties" : {
+      "skill" : 5
+    }
+  }, {
+    "id" : 20,
+    "label" : "uses",
+    "type" : "edge",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 11,
+    "outV" : 7,
+    "properties" : {
+      "skill" : 4
+    }
+  }, {
+    "id" : 21,
+    "label" : "develops",
+    "type" : "edge",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 10,
+    "outV" : 8,
+    "properties" : {
+      "since" : 2012
+    }
+  }, {
+    "id" : 22,
+    "label" : "uses",
+    "type" : "edge",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 10,
+    "outV" : 8,
+    "properties" : {
+      "skill" : 3
+    }
+  }, {
+    "id" : 23,
+    "label" : "uses",
+    "type" : "edge",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 11,
+    "outV" : 8,
+    "properties" : {
+      "skill" : 3
+    }
+  }, {
+    "id" : 24,
+    "label" : "uses",
+    "type" : "edge",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 10,
+    "outV" : 9,
+    "properties" : {
+      "skill" : 5
+    }
+  }, {
+    "id" : 25,
+    "label" : "uses",
+    "type" : "edge",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 11,
+    "outV" : 9,
+    "properties" : {
+      "skill" : 3
+    }
+  }, {
+    "id" : 26,
+    "label" : "traverses",
+    "type" : "edge",
+    "inVLabel" : "software",
+    "outVLabel" : "software",
+    "inV" : 11,
+    "outV" : 10
+  } ]
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/tinkergraph-v2d0-no-types.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/tinkergraph-v2d0-no-types.json
new file mode 100644
index 0000000..94ad061
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/tinkergraph-v2d0-no-types.json
@@ -0,0 +1,352 @@
+{
+  "vertices" : [ {
+    "id" : 1,
+    "label" : "person",
+    "properties" : {
+      "name" : [ {
+        "id" : 0,
+        "value" : "marko",
+        "label" : "name"
+      } ],
+      "location" : [ {
+        "id" : 6,
+        "value" : "san diego",
+        "label" : "location",
+        "properties" : {
+          "startTime" : 1997,
+          "endTime" : 2001
+        }
+      }, {
+        "id" : 7,
+        "value" : "santa cruz",
+        "label" : "location",
+        "properties" : {
+          "startTime" : 2001,
+          "endTime" : 2004
+        }
+      }, {
+        "id" : 8,
+        "value" : "brussels",
+        "label" : "location",
+        "properties" : {
+          "startTime" : 2004,
+          "endTime" : 2005
+        }
+      }, {
+        "id" : 9,
+        "value" : "santa fe",
+        "label" : "location",
+        "properties" : {
+          "startTime" : 2005
+        }
+      } ]
+    }
+  }, {
+    "id" : 7,
+    "label" : "person",
+    "properties" : {
+      "name" : [ {
+        "id" : 1,
+        "value" : "stephen",
+        "label" : "name"
+      } ],
+      "location" : [ {
+        "id" : 10,
+        "value" : "centreville",
+        "label" : "location",
+        "properties" : {
+          "startTime" : 1990,
+          "endTime" : 2000
+        }
+      }, {
+        "id" : 11,
+        "value" : "dulles",
+        "label" : "location",
+        "properties" : {
+          "startTime" : 2000,
+          "endTime" : 2006
+        }
+      }, {
+        "id" : 12,
+        "value" : "purcellville",
+        "label" : "location",
+        "properties" : {
+          "startTime" : 2006
+        }
+      } ]
+    }
+  }, {
+    "id" : 8,
+    "label" : "person",
+    "properties" : {
+      "name" : [ {
+        "id" : 2,
+        "value" : "matthias",
+        "label" : "name"
+      } ],
+      "location" : [ {
+        "id" : 13,
+        "value" : "bremen",
+        "label" : "location",
+        "properties" : {
+          "startTime" : 2004,
+          "endTime" : 2007
+        }
+      }, {
+        "id" : 14,
+        "value" : "baltimore",
+        "label" : "location",
+        "properties" : {
+          "startTime" : 2007,
+          "endTime" : 2011
+        }
+      }, {
+        "id" : 15,
+        "value" : "oakland",
+        "label" : "location",
+        "properties" : {
+          "startTime" : 2011,
+          "endTime" : 2014
+        }
+      }, {
+        "id" : 16,
+        "value" : "seattle",
+        "label" : "location",
+        "properties" : {
+          "startTime" : 2014
+        }
+      } ]
+    }
+  }, {
+    "id" : 9,
+    "label" : "person",
+    "properties" : {
+      "name" : [ {
+        "id" : 3,
+        "value" : "daniel",
+        "label" : "name"
+      } ],
+      "location" : [ {
+        "id" : 17,
+        "value" : "spremberg",
+        "label" : "location",
+        "properties" : {
+          "startTime" : 1982,
+          "endTime" : 2005
+        }
+      }, {
+        "id" : 18,
+        "value" : "kaiserslautern",
+        "label" : "location",
+        "properties" : {
+          "startTime" : 2005,
+          "endTime" : 2009
+        }
+      }, {
+        "id" : 19,
+        "value" : "aachen",
+        "label" : "location",
+        "properties" : {
+          "startTime" : 2009
+        }
+      } ]
+    }
+  }, {
+    "id" : 10,
+    "label" : "software",
+    "properties" : {
+      "name" : [ {
+        "id" : 4,
+        "value" : "gremlin",
+        "label" : "name"
+      } ]
+    }
+  }, {
+    "id" : 11,
+    "label" : "software",
+    "properties" : {
+      "name" : [ {
+        "id" : 5,
+        "value" : "tinkergraph",
+        "label" : "name"
+      } ]
+    }
+  } ],
+  "edges" : [ {
+    "id" : 13,
+    "label" : "develops",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 10,
+    "outV" : 1,
+    "properties" : {
+      "since" : {
+        "key" : "since",
+        "value" : 2009
+      }
+    }
+  }, {
+    "id" : 14,
+    "label" : "develops",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 11,
+    "outV" : 1,
+    "properties" : {
+      "since" : {
+        "key" : "since",
+        "value" : 2010
+      }
+    }
+  }, {
+    "id" : 15,
+    "label" : "uses",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 10,
+    "outV" : 1,
+    "properties" : {
+      "skill" : {
+        "key" : "skill",
+        "value" : 4
+      }
+    }
+  }, {
+    "id" : 16,
+    "label" : "uses",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 11,
+    "outV" : 1,
+    "properties" : {
+      "skill" : {
+        "key" : "skill",
+        "value" : 5
+      }
+    }
+  }, {
+    "id" : 17,
+    "label" : "develops",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 10,
+    "outV" : 7,
+    "properties" : {
+      "since" : {
+        "key" : "since",
+        "value" : 2010
+      }
+    }
+  }, {
+    "id" : 18,
+    "label" : "develops",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 11,
+    "outV" : 7,
+    "properties" : {
+      "since" : {
+        "key" : "since",
+        "value" : 2011
+      }
+    }
+  }, {
+    "id" : 19,
+    "label" : "uses",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 10,
+    "outV" : 7,
+    "properties" : {
+      "skill" : {
+        "key" : "skill",
+        "value" : 5
+      }
+    }
+  }, {
+    "id" : 20,
+    "label" : "uses",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 11,
+    "outV" : 7,
+    "properties" : {
+      "skill" : {
+        "key" : "skill",
+        "value" : 4
+      }
+    }
+  }, {
+    "id" : 21,
+    "label" : "develops",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 10,
+    "outV" : 8,
+    "properties" : {
+      "since" : {
+        "key" : "since",
+        "value" : 2012
+      }
+    }
+  }, {
+    "id" : 22,
+    "label" : "uses",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 10,
+    "outV" : 8,
+    "properties" : {
+      "skill" : {
+        "key" : "skill",
+        "value" : 3
+      }
+    }
+  }, {
+    "id" : 23,
+    "label" : "uses",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 11,
+    "outV" : 8,
+    "properties" : {
+      "skill" : {
+        "key" : "skill",
+        "value" : 3
+      }
+    }
+  }, {
+    "id" : 24,
+    "label" : "uses",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 10,
+    "outV" : 9,
+    "properties" : {
+      "skill" : {
+        "key" : "skill",
+        "value" : 5
+      }
+    }
+  }, {
+    "id" : 25,
+    "label" : "uses",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 11,
+    "outV" : 9,
+    "properties" : {
+      "skill" : {
+        "key" : "skill",
+        "value" : 3
+      }
+    }
+  }, {
+    "id" : 26,
+    "label" : "traverses",
+    "inVLabel" : "software",
+    "outVLabel" : "software",
+    "inV" : 11,
+    "outV" : 10
+  } ]
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/tinkergraph-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/tinkergraph-v2d0-partial.json
new file mode 100644
index 0000000..24e95ed
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/tinkergraph-v2d0-partial.json
@@ -0,0 +1,829 @@
+{
+  "@type" : "tinker:graph",
+  "@value" : {
+    "vertices" : [ {
+      "@type" : "g:Vertex",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 1
+        },
+        "label" : "person",
+        "properties" : {
+          "name" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 0
+              },
+              "value" : "marko",
+              "label" : "name"
+            }
+          } ],
+          "location" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 6
+              },
+              "value" : "san diego",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 1997
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2001
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 7
+              },
+              "value" : "santa cruz",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2001
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2004
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 8
+              },
+              "value" : "brussels",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2004
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2005
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 9
+              },
+              "value" : "santa fe",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2005
+                }
+              }
+            }
+          } ]
+        }
+      }
+    }, {
+      "@type" : "g:Vertex",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 7
+        },
+        "label" : "person",
+        "properties" : {
+          "name" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 1
+              },
+              "value" : "stephen",
+              "label" : "name"
+            }
+          } ],
+          "location" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 10
+              },
+              "value" : "centreville",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 1990
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2000
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 11
+              },
+              "value" : "dulles",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2000
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2006
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 12
+              },
+              "value" : "purcellville",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2006
+                }
+              }
+            }
+          } ]
+        }
+      }
+    }, {
+      "@type" : "g:Vertex",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 8
+        },
+        "label" : "person",
+        "properties" : {
+          "name" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 2
+              },
+              "value" : "matthias",
+              "label" : "name"
+            }
+          } ],
+          "location" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 13
+              },
+              "value" : "bremen",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2004
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2007
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 14
+              },
+              "value" : "baltimore",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2007
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2011
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 15
+              },
+              "value" : "oakland",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2011
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2014
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 16
+              },
+              "value" : "seattle",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2014
+                }
+              }
+            }
+          } ]
+        }
+      }
+    }, {
+      "@type" : "g:Vertex",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 9
+        },
+        "label" : "person",
+        "properties" : {
+          "name" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 3
+              },
+              "value" : "daniel",
+              "label" : "name"
+            }
+          } ],
+          "location" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 17
+              },
+              "value" : "spremberg",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 1982
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2005
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 18
+              },
+              "value" : "kaiserslautern",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2005
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2009
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 19
+              },
+              "value" : "aachen",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2009
+                }
+              }
+            }
+          } ]
+        }
+      }
+    }, {
+      "@type" : "g:Vertex",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 10
+        },
+        "label" : "software",
+        "properties" : {
+          "name" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 4
+              },
+              "value" : "gremlin",
+              "label" : "name"
+            }
+          } ]
+        }
+      }
+    }, {
+      "@type" : "g:Vertex",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 11
+        },
+        "label" : "software",
+        "properties" : {
+          "name" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 5
+              },
+              "value" : "tinkergraph",
+              "label" : "name"
+            }
+          } ]
+        }
+      }
+    } ],
+    "edges" : [ {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 13
+        },
+        "label" : "develops",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 10
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 1
+        },
+        "properties" : {
+          "since" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "since",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 2009
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 14
+        },
+        "label" : "develops",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 11
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 1
+        },
+        "properties" : {
+          "since" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "since",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 2010
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 15
+        },
+        "label" : "uses",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 10
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 1
+        },
+        "properties" : {
+          "skill" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "skill",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 4
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 16
+        },
+        "label" : "uses",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 11
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 1
+        },
+        "properties" : {
+          "skill" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "skill",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 5
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 17
+        },
+        "label" : "develops",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 10
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 7
+        },
+        "properties" : {
+          "since" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "since",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 2010
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 18
+        },
+        "label" : "develops",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 11
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 7
+        },
+        "properties" : {
+          "since" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "since",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 2011
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 19
+        },
+        "label" : "uses",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 10
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 7
+        },
+        "properties" : {
+          "skill" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "skill",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 5
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 20
+        },
+        "label" : "uses",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 11
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 7
+        },
+        "properties" : {
+          "skill" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "skill",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 4
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 21
+        },
+        "label" : "develops",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 10
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 8
+        },
+        "properties" : {
+          "since" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "since",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 2012
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 22
+        },
+        "label" : "uses",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 10
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 8
+        },
+        "properties" : {
+          "skill" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "skill",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 3
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 23
+        },
+        "label" : "uses",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 11
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 8
+        },
+        "properties" : {
+          "skill" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "skill",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 3
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 24
+        },
+        "label" : "uses",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 10
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 9
+        },
+        "properties" : {
+          "skill" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "skill",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 5
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 25
+        },
+        "label" : "uses",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 11
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 9
+        },
+        "properties" : {
+          "skill" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "skill",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 3
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 26
+        },
+        "label" : "traverses",
+        "inVLabel" : "software",
+        "outVLabel" : "software",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 11
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 10
+        }
+      }
+    } ]
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/tinkergraph-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/tinkergraph-v3d0.json
new file mode 100644
index 0000000..24e95ed
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/tinkergraph-v3d0.json
@@ -0,0 +1,829 @@
+{
+  "@type" : "tinker:graph",
+  "@value" : {
+    "vertices" : [ {
+      "@type" : "g:Vertex",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 1
+        },
+        "label" : "person",
+        "properties" : {
+          "name" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 0
+              },
+              "value" : "marko",
+              "label" : "name"
+            }
+          } ],
+          "location" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 6
+              },
+              "value" : "san diego",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 1997
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2001
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 7
+              },
+              "value" : "santa cruz",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2001
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2004
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 8
+              },
+              "value" : "brussels",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2004
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2005
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 9
+              },
+              "value" : "santa fe",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2005
+                }
+              }
+            }
+          } ]
+        }
+      }
+    }, {
+      "@type" : "g:Vertex",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 7
+        },
+        "label" : "person",
+        "properties" : {
+          "name" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 1
+              },
+              "value" : "stephen",
+              "label" : "name"
+            }
+          } ],
+          "location" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 10
+              },
+              "value" : "centreville",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 1990
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2000
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 11
+              },
+              "value" : "dulles",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2000
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2006
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 12
+              },
+              "value" : "purcellville",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2006
+                }
+              }
+            }
+          } ]
+        }
+      }
+    }, {
+      "@type" : "g:Vertex",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 8
+        },
+        "label" : "person",
+        "properties" : {
+          "name" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 2
+              },
+              "value" : "matthias",
+              "label" : "name"
+            }
+          } ],
+          "location" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 13
+              },
+              "value" : "bremen",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2004
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2007
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 14
+              },
+              "value" : "baltimore",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2007
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2011
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 15
+              },
+              "value" : "oakland",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2011
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2014
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 16
+              },
+              "value" : "seattle",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2014
+                }
+              }
+            }
+          } ]
+        }
+      }
+    }, {
+      "@type" : "g:Vertex",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 9
+        },
+        "label" : "person",
+        "properties" : {
+          "name" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 3
+              },
+              "value" : "daniel",
+              "label" : "name"
+            }
+          } ],
+          "location" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 17
+              },
+              "value" : "spremberg",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 1982
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2005
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 18
+              },
+              "value" : "kaiserslautern",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2005
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2009
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 19
+              },
+              "value" : "aachen",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2009
+                }
+              }
+            }
+          } ]
+        }
+      }
+    }, {
+      "@type" : "g:Vertex",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 10
+        },
+        "label" : "software",
+        "properties" : {
+          "name" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 4
+              },
+              "value" : "gremlin",
+              "label" : "name"
+            }
+          } ]
+        }
+      }
+    }, {
+      "@type" : "g:Vertex",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 11
+        },
+        "label" : "software",
+        "properties" : {
+          "name" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 5
+              },
+              "value" : "tinkergraph",
+              "label" : "name"
+            }
+          } ]
+        }
+      }
+    } ],
+    "edges" : [ {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 13
+        },
+        "label" : "develops",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 10
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 1
+        },
+        "properties" : {
+          "since" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "since",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 2009
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 14
+        },
+        "label" : "develops",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 11
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 1
+        },
+        "properties" : {
+          "since" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "since",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 2010
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 15
+        },
+        "label" : "uses",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 10
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 1
+        },
+        "properties" : {
+          "skill" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "skill",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 4
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 16
+        },
+        "label" : "uses",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 11
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 1
+        },
+        "properties" : {
+          "skill" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "skill",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 5
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 17
+        },
+        "label" : "develops",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 10
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 7
+        },
+        "properties" : {
+          "since" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "since",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 2010
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 18
+        },
+        "label" : "develops",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 11
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 7
+        },
+        "properties" : {
+          "since" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "since",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 2011
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 19
+        },
+        "label" : "uses",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 10
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 7
+        },
+        "properties" : {
+          "skill" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "skill",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 5
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 20
+        },
+        "label" : "uses",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 11
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 7
+        },
+        "properties" : {
+          "skill" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "skill",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 4
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 21
+        },
+        "label" : "develops",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 10
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 8
+        },
+        "properties" : {
+          "since" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "since",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 2012
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 22
+        },
+        "label" : "uses",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 10
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 8
+        },
+        "properties" : {
+          "skill" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "skill",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 3
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 23
+        },
+        "label" : "uses",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 11
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 8
+        },
+        "properties" : {
+          "skill" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "skill",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 3
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 24
+        },
+        "label" : "uses",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 10
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 9
+        },
+        "properties" : {
+          "skill" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "skill",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 5
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 25
+        },
+        "label" : "uses",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 11
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 9
+        },
+        "properties" : {
+          "skill" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "skill",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 3
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 26
+        },
+        "label" : "traverses",
+        "inVLabel" : "software",
+        "outVLabel" : "software",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 11
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 10
+        }
+      }
+    } ]
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/traversalmetrics-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/traversalmetrics-v2d0-partial.json
new file mode 100644
index 0000000..fdd18a4
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/traversalmetrics-v2d0-partial.json
@@ -0,0 +1,114 @@
+{
+  "@type" : "g:TraversalMetrics",
+  "@value" : {
+    "dur" : {
+      "@type" : "g:Double",
+      "@value" : 0.004
+    },
+    "metrics" : [ {
+      "@type" : "g:Metrics",
+      "@value" : {
+        "dur" : {
+          "@type" : "g:Double",
+          "@value" : 100.0
+        },
+        "counts" : {
+          "traverserCount" : {
+            "@type" : "g:Int64",
+            "@value" : 4
+          },
+          "elementCount" : {
+            "@type" : "g:Int64",
+            "@value" : 4
+          }
+        },
+        "name" : "TinkerGraphStep(vertex,[~label.eq(person)])",
+        "annotations" : {
+          "percentDur" : {
+            "@type" : "g:Double",
+            "@value" : 25.0
+          }
+        },
+        "id" : "7.0.0()"
+      }
+    }, {
+      "@type" : "g:Metrics",
+      "@value" : {
+        "dur" : {
+          "@type" : "g:Double",
+          "@value" : 100.0
+        },
+        "counts" : {
+          "traverserCount" : {
+            "@type" : "g:Int64",
+            "@value" : 13
+          },
+          "elementCount" : {
+            "@type" : "g:Int64",
+            "@value" : 13
+          }
+        },
+        "name" : "VertexStep(OUT,vertex)",
+        "annotations" : {
+          "percentDur" : {
+            "@type" : "g:Double",
+            "@value" : 25.0
+          }
+        },
+        "id" : "2.0.0()"
+      }
+    }, {
+      "@type" : "g:Metrics",
+      "@value" : {
+        "dur" : {
+          "@type" : "g:Double",
+          "@value" : 100.0
+        },
+        "counts" : {
+          "traverserCount" : {
+            "@type" : "g:Int64",
+            "@value" : 7
+          },
+          "elementCount" : {
+            "@type" : "g:Int64",
+            "@value" : 7
+          }
+        },
+        "name" : "VertexStep(OUT,vertex)",
+        "annotations" : {
+          "percentDur" : {
+            "@type" : "g:Double",
+            "@value" : 25.0
+          }
+        },
+        "id" : "3.0.0()"
+      }
+    }, {
+      "@type" : "g:Metrics",
+      "@value" : {
+        "dur" : {
+          "@type" : "g:Double",
+          "@value" : 100.0
+        },
+        "counts" : {
+          "traverserCount" : {
+            "@type" : "g:Int64",
+            "@value" : 1
+          },
+          "elementCount" : {
+            "@type" : "g:Int64",
+            "@value" : 1
+          }
+        },
+        "name" : "TreeStep",
+        "annotations" : {
+          "percentDur" : {
+            "@type" : "g:Double",
+            "@value" : 25.0
+          }
+        },
+        "id" : "4.0.0()"
+      }
+    } ]
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/traversalmetrics-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/traversalmetrics-v3d0.json
new file mode 100644
index 0000000..46f7636
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/traversalmetrics-v3d0.json
@@ -0,0 +1,109 @@
+{
+  "@type" : "g:TraversalMetrics",
+  "@value" : {
+    "@type" : "g:Map",
+    "@value" : [ "dur", {
+      "@type" : "g:Double",
+      "@value" : 0.004
+    }, "metrics", {
+      "@type" : "g:List",
+      "@value" : [ {
+        "@type" : "g:Metrics",
+        "@value" : {
+          "@type" : "g:Map",
+          "@value" : [ "dur", {
+            "@type" : "g:Double",
+            "@value" : 100.0
+          }, "counts", {
+            "@type" : "g:Map",
+            "@value" : [ "traverserCount", {
+              "@type" : "g:Int64",
+              "@value" : 4
+            }, "elementCount", {
+              "@type" : "g:Int64",
+              "@value" : 4
+            } ]
+          }, "name", "TinkerGraphStep(vertex,[~label.eq(person)])", "annotations", {
+            "@type" : "g:Map",
+            "@value" : [ "percentDur", {
+              "@type" : "g:Double",
+              "@value" : 25.0
+            } ]
+          }, "id", "7.0.0()" ]
+        }
+      }, {
+        "@type" : "g:Metrics",
+        "@value" : {
+          "@type" : "g:Map",
+          "@value" : [ "dur", {
+            "@type" : "g:Double",
+            "@value" : 100.0
+          }, "counts", {
+            "@type" : "g:Map",
+            "@value" : [ "traverserCount", {
+              "@type" : "g:Int64",
+              "@value" : 13
+            }, "elementCount", {
+              "@type" : "g:Int64",
+              "@value" : 13
+            } ]
+          }, "name", "VertexStep(OUT,vertex)", "annotations", {
+            "@type" : "g:Map",
+            "@value" : [ "percentDur", {
+              "@type" : "g:Double",
+              "@value" : 25.0
+            } ]
+          }, "id", "2.0.0()" ]
+        }
+      }, {
+        "@type" : "g:Metrics",
+        "@value" : {
+          "@type" : "g:Map",
+          "@value" : [ "dur", {
+            "@type" : "g:Double",
+            "@value" : 100.0
+          }, "counts", {
+            "@type" : "g:Map",
+            "@value" : [ "traverserCount", {
+              "@type" : "g:Int64",
+              "@value" : 7
+            }, "elementCount", {
+              "@type" : "g:Int64",
+              "@value" : 7
+            } ]
+          }, "name", "VertexStep(OUT,vertex)", "annotations", {
+            "@type" : "g:Map",
+            "@value" : [ "percentDur", {
+              "@type" : "g:Double",
+              "@value" : 25.0
+            } ]
+          }, "id", "3.0.0()" ]
+        }
+      }, {
+        "@type" : "g:Metrics",
+        "@value" : {
+          "@type" : "g:Map",
+          "@value" : [ "dur", {
+            "@type" : "g:Double",
+            "@value" : 100.0
+          }, "counts", {
+            "@type" : "g:Map",
+            "@value" : [ "traverserCount", {
+              "@type" : "g:Int64",
+              "@value" : 1
+            }, "elementCount", {
+              "@type" : "g:Int64",
+              "@value" : 1
+            } ]
+          }, "name", "TreeStep", "annotations", {
+            "@type" : "g:Map",
+            "@value" : [ "percentDur", {
+              "@type" : "g:Double",
+              "@value" : 25.0
+            } ]
+          }, "id", "4.0.0()" ]
+        }
+      } ]
+    } ]
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/traverser-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/traverser-v2d0-partial.json
new file mode 100644
index 0000000..a59a29e
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/traverser-v2d0-partial.json
@@ -0,0 +1,109 @@
+{
+  "@type" : "g:Traverser",
+  "@value" : {
+    "bulk" : {
+      "@type" : "g:Int64",
+      "@value" : 1
+    },
+    "value" : {
+      "@type" : "g:Vertex",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 1
+        },
+        "label" : "person",
+        "properties" : {
+          "name" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 0
+              },
+              "value" : "marko",
+              "label" : "name"
+            }
+          } ],
+          "location" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 6
+              },
+              "value" : "san diego",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 1997
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2001
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 7
+              },
+              "value" : "santa cruz",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2001
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2004
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 8
+              },
+              "value" : "brussels",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2004
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2005
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 9
+              },
+              "value" : "santa fe",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2005
+                }
+              }
+            }
+          } ]
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/traverser-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/traverser-v3d0.json
new file mode 100644
index 0000000..a59a29e
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/traverser-v3d0.json
@@ -0,0 +1,109 @@
+{
+  "@type" : "g:Traverser",
+  "@value" : {
+    "bulk" : {
+      "@type" : "g:Int64",
+      "@value" : 1
+    },
+    "value" : {
+      "@type" : "g:Vertex",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 1
+        },
+        "label" : "person",
+        "properties" : {
+          "name" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 0
+              },
+              "value" : "marko",
+              "label" : "name"
+            }
+          } ],
+          "location" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 6
+              },
+              "value" : "san diego",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 1997
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2001
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 7
+              },
+              "value" : "santa cruz",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2001
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2004
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 8
+              },
+              "value" : "brussels",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2004
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2005
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 9
+              },
+              "value" : "santa fe",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2005
+                }
+              }
+            }
+          } ]
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/uuid-v2d0-no-types.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/uuid-v2d0-no-types.json
new file mode 100644
index 0000000..b36ff96
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/uuid-v2d0-no-types.json
@@ -0,0 +1 @@
+"41d2e28a-20a4-4ab0-b379-d810dede3786"
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/uuid-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/uuid-v2d0-partial.json
new file mode 100644
index 0000000..1cf09f0
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/uuid-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:UUID",
+  "@value" : "41d2e28a-20a4-4ab0-b379-d810dede3786"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/uuid-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/uuid-v3d0.json
new file mode 100644
index 0000000..1cf09f0
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/uuid-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "g:UUID",
+  "@value" : "41d2e28a-20a4-4ab0-b379-d810dede3786"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/vertex-v1d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/vertex-v1d0.json
new file mode 100644
index 0000000..a885f58
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/vertex-v1d0.json
@@ -0,0 +1,39 @@
+{
+  "id" : 1,
+  "label" : "person",
+  "type" : "vertex",
+  "properties" : {
+    "name" : [ {
+      "id" : 0,
+      "value" : "marko"
+    } ],
+    "location" : [ {
+      "id" : 6,
+      "value" : "san diego",
+      "properties" : {
+        "startTime" : 1997,
+        "endTime" : 2001
+      }
+    }, {
+      "id" : 7,
+      "value" : "santa cruz",
+      "properties" : {
+        "startTime" : 2001,
+        "endTime" : 2004
+      }
+    }, {
+      "id" : 8,
+      "value" : "brussels",
+      "properties" : {
+        "startTime" : 2004,
+        "endTime" : 2005
+      }
+    }, {
+      "id" : 9,
+      "value" : "santa fe",
+      "properties" : {
+        "startTime" : 2005
+      }
+    } ]
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/vertex-v2d0-no-types.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/vertex-v2d0-no-types.json
new file mode 100644
index 0000000..8e6155f
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/vertex-v2d0-no-types.json
@@ -0,0 +1,43 @@
+{
+  "id" : 1,
+  "label" : "person",
+  "properties" : {
+    "name" : [ {
+      "id" : 0,
+      "value" : "marko",
+      "label" : "name"
+    } ],
+    "location" : [ {
+      "id" : 6,
+      "value" : "san diego",
+      "label" : "location",
+      "properties" : {
+        "startTime" : 1997,
+        "endTime" : 2001
+      }
+    }, {
+      "id" : 7,
+      "value" : "santa cruz",
+      "label" : "location",
+      "properties" : {
+        "startTime" : 2001,
+        "endTime" : 2004
+      }
+    }, {
+      "id" : 8,
+      "value" : "brussels",
+      "label" : "location",
+      "properties" : {
+        "startTime" : 2004,
+        "endTime" : 2005
+      }
+    }, {
+      "id" : 9,
+      "value" : "santa fe",
+      "label" : "location",
+      "properties" : {
+        "startTime" : 2005
+      }
+    } ]
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/vertex-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/vertex-v2d0-partial.json
new file mode 100644
index 0000000..f102230
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/vertex-v2d0-partial.json
@@ -0,0 +1,100 @@
+{
+  "@type" : "g:Vertex",
+  "@value" : {
+    "id" : {
+      "@type" : "g:Int32",
+      "@value" : 1
+    },
+    "label" : "person",
+    "properties" : {
+      "name" : [ {
+        "@type" : "g:VertexProperty",
+        "@value" : {
+          "id" : {
+            "@type" : "g:Int64",
+            "@value" : 0
+          },
+          "value" : "marko",
+          "label" : "name"
+        }
+      } ],
+      "location" : [ {
+        "@type" : "g:VertexProperty",
+        "@value" : {
+          "id" : {
+            "@type" : "g:Int64",
+            "@value" : 6
+          },
+          "value" : "san diego",
+          "label" : "location",
+          "properties" : {
+            "startTime" : {
+              "@type" : "g:Int32",
+              "@value" : 1997
+            },
+            "endTime" : {
+              "@type" : "g:Int32",
+              "@value" : 2001
+            }
+          }
+        }
+      }, {
+        "@type" : "g:VertexProperty",
+        "@value" : {
+          "id" : {
+            "@type" : "g:Int64",
+            "@value" : 7
+          },
+          "value" : "santa cruz",
+          "label" : "location",
+          "properties" : {
+            "startTime" : {
+              "@type" : "g:Int32",
+              "@value" : 2001
+            },
+            "endTime" : {
+              "@type" : "g:Int32",
+              "@value" : 2004
+            }
+          }
+        }
+      }, {
+        "@type" : "g:VertexProperty",
+        "@value" : {
+          "id" : {
+            "@type" : "g:Int64",
+            "@value" : 8
+          },
+          "value" : "brussels",
+          "label" : "location",
+          "properties" : {
+            "startTime" : {
+              "@type" : "g:Int32",
+              "@value" : 2004
+            },
+            "endTime" : {
+              "@type" : "g:Int32",
+              "@value" : 2005
+            }
+          }
+        }
+      }, {
+        "@type" : "g:VertexProperty",
+        "@value" : {
+          "id" : {
+            "@type" : "g:Int64",
+            "@value" : 9
+          },
+          "value" : "santa fe",
+          "label" : "location",
+          "properties" : {
+            "startTime" : {
+              "@type" : "g:Int32",
+              "@value" : 2005
+            }
+          }
+        }
+      } ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/vertex-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/vertex-v3d0.json
new file mode 100644
index 0000000..f102230
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/vertex-v3d0.json
@@ -0,0 +1,100 @@
+{
+  "@type" : "g:Vertex",
+  "@value" : {
+    "id" : {
+      "@type" : "g:Int32",
+      "@value" : 1
+    },
+    "label" : "person",
+    "properties" : {
+      "name" : [ {
+        "@type" : "g:VertexProperty",
+        "@value" : {
+          "id" : {
+            "@type" : "g:Int64",
+            "@value" : 0
+          },
+          "value" : "marko",
+          "label" : "name"
+        }
+      } ],
+      "location" : [ {
+        "@type" : "g:VertexProperty",
+        "@value" : {
+          "id" : {
+            "@type" : "g:Int64",
+            "@value" : 6
+          },
+          "value" : "san diego",
+          "label" : "location",
+          "properties" : {
+            "startTime" : {
+              "@type" : "g:Int32",
+              "@value" : 1997
+            },
+            "endTime" : {
+              "@type" : "g:Int32",
+              "@value" : 2001
+            }
+          }
+        }
+      }, {
+        "@type" : "g:VertexProperty",
+        "@value" : {
+          "id" : {
+            "@type" : "g:Int64",
+            "@value" : 7
+          },
+          "value" : "santa cruz",
+          "label" : "location",
+          "properties" : {
+            "startTime" : {
+              "@type" : "g:Int32",
+              "@value" : 2001
+            },
+            "endTime" : {
+              "@type" : "g:Int32",
+              "@value" : 2004
+            }
+          }
+        }
+      }, {
+        "@type" : "g:VertexProperty",
+        "@value" : {
+          "id" : {
+            "@type" : "g:Int64",
+            "@value" : 8
+          },
+          "value" : "brussels",
+          "label" : "location",
+          "properties" : {
+            "startTime" : {
+              "@type" : "g:Int32",
+              "@value" : 2004
+            },
+            "endTime" : {
+              "@type" : "g:Int32",
+              "@value" : 2005
+            }
+          }
+        }
+      }, {
+        "@type" : "g:VertexProperty",
+        "@value" : {
+          "id" : {
+            "@type" : "g:Int64",
+            "@value" : 9
+          },
+          "value" : "santa fe",
+          "label" : "location",
+          "properties" : {
+            "startTime" : {
+              "@type" : "g:Int32",
+              "@value" : 2005
+            }
+          }
+        }
+      } ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/vertexproperty-v1d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/vertexproperty-v1d0.json
new file mode 100644
index 0000000..74025a8
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/vertexproperty-v1d0.json
@@ -0,0 +1,5 @@
+{
+  "id" : 0,
+  "value" : "marko",
+  "label" : "name"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/vertexproperty-v2d0-no-types.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/vertexproperty-v2d0-no-types.json
new file mode 100644
index 0000000..74025a8
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/vertexproperty-v2d0-no-types.json
@@ -0,0 +1,5 @@
+{
+  "id" : 0,
+  "value" : "marko",
+  "label" : "name"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/vertexproperty-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/vertexproperty-v2d0-partial.json
new file mode 100644
index 0000000..af184b1
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/vertexproperty-v2d0-partial.json
@@ -0,0 +1,11 @@
+{
+  "@type" : "g:VertexProperty",
+  "@value" : {
+    "id" : {
+      "@type" : "g:Int64",
+      "@value" : 0
+    },
+    "value" : "marko",
+    "label" : "name"
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/vertexproperty-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/vertexproperty-v3d0.json
new file mode 100644
index 0000000..af184b1
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/vertexproperty-v3d0.json
@@ -0,0 +1,11 @@
+{
+  "@type" : "g:VertexProperty",
+  "@value" : {
+    "id" : {
+      "@type" : "g:Int64",
+      "@value" : 0
+    },
+    "value" : "marko",
+    "label" : "name"
+  }
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/year-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/year-v2d0-partial.json
new file mode 100644
index 0000000..ff420bc
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/year-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:Year",
+  "@value" : "2016"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/year-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/year-v3d0.json
new file mode 100644
index 0000000..ff420bc
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/year-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:Year",
+  "@value" : "2016"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/yearmonth-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/yearmonth-v2d0-partial.json
new file mode 100644
index 0000000..98a5e27
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/yearmonth-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:YearMonth",
+  "@value" : "2016-06"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/yearmonth-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/yearmonth-v3d0.json
new file mode 100644
index 0000000..98a5e27
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/yearmonth-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:YearMonth",
+  "@value" : "2016-06"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/zoneddatetime-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/zoneddatetime-v2d0-partial.json
new file mode 100644
index 0000000..367fc47
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/zoneddatetime-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:ZonedDateTime",
+  "@value" : "2016-12-23T12:12:24.000000036+02:00[GMT+02:00]"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/zoneddatetime-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/zoneddatetime-v3d0.json
new file mode 100644
index 0000000..367fc47
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/zoneddatetime-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:ZonedDateTime",
+  "@value" : "2016-12-23T12:12:24.000000036+02:00[GMT+02:00]"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/zoneoffset-v2d0-partial.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/zoneoffset-v2d0-partial.json
new file mode 100644
index 0000000..8591794
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/zoneoffset-v2d0-partial.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:ZoneOffset",
+  "@value" : "+03:06:09"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/zoneoffset-v3d0.json b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/zoneoffset-v3d0.json
new file mode 100644
index 0000000..8591794
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_5_0/zoneoffset-v3d0.json
@@ -0,0 +1,4 @@
+{
+  "@type" : "gx:ZoneOffset",
+  "@value" : "+03:06:09"
+}
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/authenticationchallenge-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/authenticationchallenge-v3d0.kryo
new file mode 100644
index 0000000..baf91ac
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/authenticationchallenge-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/authenticationresponse-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/authenticationresponse-v3d0.kryo
new file mode 100644
index 0000000..1f99f2a
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/authenticationresponse-v3d0.kryo
@@ -0,0 +1 @@
+Ëh%x’D™ž¼\j§<S—authenticatioîsaslMechanisíPLAIÎsasìAHN0ZXBocGhlbgBwYXNzd29yZA=½
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/barrier-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/barrier-v1d0.kryo
new file mode 100644
index 0000000..40fdece
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/barrier-v1d0.kryo
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/barrier-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/barrier-v3d0.kryo
new file mode 100644
index 0000000..40fdece
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/barrier-v3d0.kryo
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/bigdecimal-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/bigdecimal-v1d0.kryo
new file mode 100644
index 0000000..d4f40e0
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/bigdecimal-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/bigdecimal-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/bigdecimal-v3d0.kryo
new file mode 100644
index 0000000..d4f40e0
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/bigdecimal-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/biginteger-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/biginteger-v1d0.kryo
new file mode 100644
index 0000000..f424ac6
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/biginteger-v1d0.kryo
@@ -0,0 +1 @@
+ÆãÂýтZÏ}Dvú±
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/biginteger-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/biginteger-v3d0.kryo
new file mode 100644
index 0000000..f424ac6
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/biginteger-v3d0.kryo
@@ -0,0 +1 @@
+ÆãÂýтZÏ}Dvú±
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/binding-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/binding-v1d0.kryo
new file mode 100644
index 0000000..103143b
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/binding-v1d0.kryo
@@ -0,0 +1 @@
+‚x
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/binding-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/binding-v3d0.kryo
new file mode 100644
index 0000000..103143b
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/binding-v3d0.kryo
@@ -0,0 +1 @@
+‚x
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/bulkset-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/bulkset-v1d0.kryo
new file mode 100644
index 0000000..5fda27a
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/bulkset-v1d0.kryo
@@ -0,0 +1 @@
+markïjosè
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/bulkset-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/bulkset-v3d0.kryo
new file mode 100644
index 0000000..5fda27a
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/bulkset-v3d0.kryo
@@ -0,0 +1 @@
+markïjosè
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/byte-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/byte-v1d0.kryo
new file mode 100644
index 0000000..6b2aaa7
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/byte-v1d0.kryo
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/byte-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/byte-v3d0.kryo
new file mode 100644
index 0000000..6b2aaa7
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/byte-v3d0.kryo
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/bytebuffer-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/bytebuffer-v1d0.kryo
new file mode 100644
index 0000000..ba94b5d
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/bytebuffer-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/bytebuffer-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/bytebuffer-v3d0.kryo
new file mode 100644
index 0000000..ba94b5d
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/bytebuffer-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/bytecode-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/bytecode-v1d0.kryo
new file mode 100644
index 0000000..edf8dd4
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/bytecode-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/bytecode-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/bytecode-v3d0.kryo
new file mode 100644
index 0000000..edf8dd4
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/bytecode-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/cardinality-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/cardinality-v1d0.kryo
new file mode 100644
index 0000000..71bd63e
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/cardinality-v1d0.kryo
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/cardinality-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/cardinality-v3d0.kryo
new file mode 100644
index 0000000..71bd63e
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/cardinality-v3d0.kryo
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/char-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/char-v1d0.kryo
new file mode 100644
index 0000000..718882c
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/char-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/char-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/char-v3d0.kryo
new file mode 100644
index 0000000..718882c
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/char-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/class-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/class-v1d0.kryo
new file mode 100644
index 0000000..e8b65af
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/class-v1d0.kryo
@@ -0,0 +1 @@
+java.io.Filå
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/class-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/class-v3d0.kryo
new file mode 100644
index 0000000..e8b65af
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/class-v3d0.kryo
@@ -0,0 +1 @@
+java.io.Filå
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/column-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/column-v1d0.kryo
new file mode 100644
index 0000000..40fdece
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/column-v1d0.kryo
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/column-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/column-v3d0.kryo
new file mode 100644
index 0000000..40fdece
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/column-v3d0.kryo
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/date-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/date-v1d0.kryo
new file mode 100644
index 0000000..a86f98f
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/date-v1d0.kryo
@@ -0,0 +1 @@
+‡·¿ù+
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/date-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/date-v3d0.kryo
new file mode 100644
index 0000000..a86f98f
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/date-v3d0.kryo
@@ -0,0 +1 @@
+‡·¿ù+
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/direction-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/direction-v1d0.kryo
new file mode 100644
index 0000000..40fdece
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/direction-v1d0.kryo
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/direction-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/direction-v3d0.kryo
new file mode 100644
index 0000000..40fdece
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/direction-v3d0.kryo
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/double-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/double-v1d0.kryo
new file mode 100644
index 0000000..36506ac
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/double-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/double-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/double-v3d0.kryo
new file mode 100644
index 0000000..36506ac
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/double-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/duration-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/duration-v1d0.kryo
new file mode 100644
index 0000000..d640ae0
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/duration-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/duration-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/duration-v3d0.kryo
new file mode 100644
index 0000000..d640ae0
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/duration-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/edge-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/edge-v1d0.kryo
new file mode 100644
index 0000000..d2a2492
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/edge-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/edge-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/edge-v3d0.kryo
new file mode 100644
index 0000000..6dfbefb
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/edge-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/float-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/float-v1d0.kryo
new file mode 100644
index 0000000..19a8865
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/float-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/float-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/float-v3d0.kryo
new file mode 100644
index 0000000..19a8865
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/float-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/inetaddress-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/inetaddress-v1d0.kryo
new file mode 100644
index 0000000..af797a5
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/inetaddress-v1d0.kryo
@@ -0,0 +1 @@
+localhosô
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/inetaddress-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/inetaddress-v3d0.kryo
new file mode 100644
index 0000000..af797a5
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/inetaddress-v3d0.kryo
@@ -0,0 +1 @@
+localhosô
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/instant-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/instant-v1d0.kryo
new file mode 100644
index 0000000..d9466cd
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/instant-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/instant-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/instant-v3d0.kryo
new file mode 100644
index 0000000..d9466cd
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/instant-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/integer-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/integer-v1d0.kryo
new file mode 100644
index 0000000..ff28336
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/integer-v1d0.kryo
@@ -0,0 +1 @@
+È
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/integer-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/integer-v3d0.kryo
new file mode 100644
index 0000000..ff28336
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/integer-v3d0.kryo
@@ -0,0 +1 @@
+È
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/lambda-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/lambda-v1d0.kryo
new file mode 100644
index 0000000..463661d
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/lambda-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/lambda-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/lambda-v3d0.kryo
new file mode 100644
index 0000000..463661d
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/lambda-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/localdate-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/localdate-v1d0.kryo
new file mode 100644
index 0000000..f82dd16
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/localdate-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/localdate-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/localdate-v3d0.kryo
new file mode 100644
index 0000000..f82dd16
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/localdate-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/localdatetime-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/localdatetime-v1d0.kryo
new file mode 100644
index 0000000..97eae64
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/localdatetime-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/localdatetime-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/localdatetime-v3d0.kryo
new file mode 100644
index 0000000..97eae64
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/localdatetime-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/localtime-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/localtime-v1d0.kryo
new file mode 100644
index 0000000..1b5bfa4
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/localtime-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/localtime-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/localtime-v3d0.kryo
new file mode 100644
index 0000000..1b5bfa4
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/localtime-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/long-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/long-v1d0.kryo
new file mode 100644
index 0000000..ff28336
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/long-v1d0.kryo
@@ -0,0 +1 @@
+È
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/long-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/long-v3d0.kryo
new file mode 100644
index 0000000..ff28336
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/long-v3d0.kryo
@@ -0,0 +1 @@
+È
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/metrics-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/metrics-v1d0.kryo
new file mode 100644
index 0000000..d94cd24
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/metrics-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/metrics-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/metrics-v3d0.kryo
new file mode 100644
index 0000000..f65dd63
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/metrics-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/monthday-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/monthday-v1d0.kryo
new file mode 100644
index 0000000..5acab8f
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/monthday-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/monthday-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/monthday-v3d0.kryo
new file mode 100644
index 0000000..5acab8f
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/monthday-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/offsetdatetime-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/offsetdatetime-v1d0.kryo
new file mode 100644
index 0000000..6bb92d0
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/offsetdatetime-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/offsetdatetime-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/offsetdatetime-v3d0.kryo
new file mode 100644
index 0000000..6bb92d0
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/offsetdatetime-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/offsettime-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/offsettime-v1d0.kryo
new file mode 100644
index 0000000..d1621aa
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/offsettime-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/offsettime-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/offsettime-v3d0.kryo
new file mode 100644
index 0000000..d1621aa
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/offsettime-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/operator-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/operator-v1d0.kryo
new file mode 100644
index 0000000..40fdece
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/operator-v1d0.kryo
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/operator-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/operator-v3d0.kryo
new file mode 100644
index 0000000..40fdece
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/operator-v3d0.kryo
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/order-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/order-v1d0.kryo
new file mode 100644
index 0000000..40fdece
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/order-v1d0.kryo
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/order-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/order-v3d0.kryo
new file mode 100644
index 0000000..40fdece
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/order-v3d0.kryo
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/p-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/p-v1d0.kryo
new file mode 100644
index 0000000..3c676a8
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/p-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/p-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/p-v3d0.kryo
new file mode 100644
index 0000000..3c676a8
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/p-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/pand-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/pand-v1d0.kryo
new file mode 100644
index 0000000..5477e40
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/pand-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/pand-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/pand-v3d0.kryo
new file mode 100644
index 0000000..5477e40
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/pand-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/path-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/path-v1d0.kryo
new file mode 100644
index 0000000..bac203d
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/path-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/path-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/path-v3d0.kryo
new file mode 100644
index 0000000..bac203d
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/path-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/period-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/period-v1d0.kryo
new file mode 100644
index 0000000..f04e9c8
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/period-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/period-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/period-v3d0.kryo
new file mode 100644
index 0000000..f04e9c8
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/period-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/pick-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/pick-v1d0.kryo
new file mode 100644
index 0000000..40fdece
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/pick-v1d0.kryo
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/pick-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/pick-v3d0.kryo
new file mode 100644
index 0000000..40fdece
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/pick-v3d0.kryo
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/pop-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/pop-v1d0.kryo
new file mode 100644
index 0000000..c8c7811
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/pop-v1d0.kryo
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/pop-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/pop-v3d0.kryo
new file mode 100644
index 0000000..c8c7811
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/pop-v3d0.kryo
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/por-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/por-v1d0.kryo
new file mode 100644
index 0000000..8b8ebb4
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/por-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/por-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/por-v3d0.kryo
new file mode 100644
index 0000000..8b8ebb4
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/por-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/property-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/property-v1d0.kryo
new file mode 100644
index 0000000..133ac6f
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/property-v1d0.kryo
@@ -0,0 +1 @@
+sincå²
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/property-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/property-v3d0.kryo
new file mode 100644
index 0000000..a7d9c27
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/property-v3d0.kryo
@@ -0,0 +1 @@
+sincå²developó
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/pwithin-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/pwithin-v1d0.kryo
new file mode 100644
index 0000000..35dfe21
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/pwithin-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/pwithin-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/pwithin-v3d0.kryo
new file mode 100644
index 0000000..35dfe21
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/pwithin-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/pwithout-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/pwithout-v1d0.kryo
new file mode 100644
index 0000000..50f14cf
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/pwithout-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/pwithout-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/pwithout-v3d0.kryo
new file mode 100644
index 0000000..50f14cf
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/pwithout-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/scope-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/scope-v1d0.kryo
new file mode 100644
index 0000000..71bd63e
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/scope-v1d0.kryo
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/scope-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/scope-v3d0.kryo
new file mode 100644
index 0000000..71bd63e
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/scope-v3d0.kryo
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/sessionclose-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/sessionclose-v3d0.kryo
new file mode 100644
index 0000000..1bad6a1
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/sessionclose-v3d0.kryo
@@ -0,0 +1 @@
+Ëh%x’D™ž¼\j§<S—sessioîclosåsessioîunique-session-identifieò
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/sessioneval-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/sessioneval-v3d0.kryo
new file mode 100644
index 0000000..f551b96
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/sessioneval-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/sessionevalaliased-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/sessionevalaliased-v3d0.kryo
new file mode 100644
index 0000000..8bb5889
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/sessionevalaliased-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/sessionlesseval-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/sessionlesseval-v3d0.kryo
new file mode 100644
index 0000000..fd84e20
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/sessionlesseval-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/sessionlessevalaliased-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/sessionlessevalaliased-v3d0.kryo
new file mode 100644
index 0000000..d3745be
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/sessionlessevalaliased-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/short-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/short-v1d0.kryo
new file mode 100644
index 0000000..6060b89
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/short-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/short-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/short-v3d0.kryo
new file mode 100644
index 0000000..6060b89
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/short-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/standardresult-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/standardresult-v3d0.kryo
new file mode 100644
index 0000000..06c5d8a
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/standardresult-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/stargraph-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/stargraph-v1d0.kryo
new file mode 100644
index 0000000..9947842
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/stargraph-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/stargraph-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/stargraph-v3d0.kryo
new file mode 100644
index 0000000..9947842
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/stargraph-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/t-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/t-v1d0.kryo
new file mode 100644
index 0000000..40fdece
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/t-v1d0.kryo
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/t-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/t-v3d0.kryo
new file mode 100644
index 0000000..40fdece
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/t-v3d0.kryo
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/textp-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/textp-v1d0.kryo
new file mode 100644
index 0000000..d71eb0f
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/textp-v1d0.kryo
@@ -0,0 +1 @@
+containinçarë
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/textp-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/textp-v3d0.kryo
new file mode 100644
index 0000000..d71eb0f
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/textp-v3d0.kryo
@@ -0,0 +1 @@
+containinçarë
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/timestamp-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/timestamp-v1d0.kryo
new file mode 100644
index 0000000..a86f98f
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/timestamp-v1d0.kryo
@@ -0,0 +1 @@
+‡·¿ù+
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/timestamp-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/timestamp-v3d0.kryo
new file mode 100644
index 0000000..a86f98f
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/timestamp-v3d0.kryo
@@ -0,0 +1 @@
+‡·¿ù+
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/tinkergraph-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/tinkergraph-v1d0.kryo
new file mode 100644
index 0000000..5789986
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/tinkergraph-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/tinkergraph-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/tinkergraph-v3d0.kryo
new file mode 100644
index 0000000..5789986
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/tinkergraph-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/traversalmetrics-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/traversalmetrics-v1d0.kryo
new file mode 100644
index 0000000..eef8b5f
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/traversalmetrics-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/traversalmetrics-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/traversalmetrics-v3d0.kryo
new file mode 100644
index 0000000..5ec44fd
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/traversalmetrics-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/traverser-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/traverser-v1d0.kryo
new file mode 100644
index 0000000..cc019f0
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/traverser-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/traverser-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/traverser-v3d0.kryo
new file mode 100644
index 0000000..7c1fb0d
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/traverser-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/tree-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/tree-v1d0.kryo
new file mode 100644
index 0000000..682529f
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/tree-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/tree-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/tree-v3d0.kryo
new file mode 100644
index 0000000..d5a9dd9
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/tree-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/uuid-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/uuid-v1d0.kryo
new file mode 100644
index 0000000..34fc35d
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/uuid-v1d0.kryo
@@ -0,0 +1 @@
+AÒ⊠¤J°³yØÞÞ7†
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/uuid-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/uuid-v3d0.kryo
new file mode 100644
index 0000000..34fc35d
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/uuid-v3d0.kryo
@@ -0,0 +1 @@
+AÒ⊠¤J°³yØÞÞ7†
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/vertex-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/vertex-v1d0.kryo
new file mode 100644
index 0000000..c58ac46
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/vertex-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/vertex-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/vertex-v3d0.kryo
new file mode 100644
index 0000000..4464039
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/vertex-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/vertexproperty-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/vertexproperty-v1d0.kryo
new file mode 100644
index 0000000..3b74daa
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/vertexproperty-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/vertexproperty-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/vertexproperty-v3d0.kryo
new file mode 100644
index 0000000..95f8be0
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/vertexproperty-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/year-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/year-v1d0.kryo
new file mode 100644
index 0000000..2ec2ef9
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/year-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/year-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/year-v3d0.kryo
new file mode 100644
index 0000000..2ec2ef9
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/year-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/yearmonth-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/yearmonth-v1d0.kryo
new file mode 100644
index 0000000..47e3a3e
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/yearmonth-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/yearmonth-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/yearmonth-v3d0.kryo
new file mode 100644
index 0000000..47e3a3e
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/yearmonth-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/zoneddatetime-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/zoneddatetime-v1d0.kryo
new file mode 100644
index 0000000..3ebbce5
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/zoneddatetime-v1d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/zoneddatetime-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/zoneddatetime-v3d0.kryo
new file mode 100644
index 0000000..3ebbce5
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/zoneddatetime-v3d0.kryo
Binary files differ
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/zoneoffset-v1d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/zoneoffset-v1d0.kryo
new file mode 100644
index 0000000..4d34f9c
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/zoneoffset-v1d0.kryo
@@ -0,0 +1 @@
++03:06:0¹
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/zoneoffset-v3d0.kryo b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/zoneoffset-v3d0.kryo
new file mode 100644
index 0000000..4d34f9c
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_5_0/zoneoffset-v3d0.kryo
@@ -0,0 +1 @@
++03:06:0¹
\ No newline at end of file
diff --git a/gremlin-tools/pom.xml b/gremlin-tools/pom.xml
index 50e6a0d..465c47a 100644
--- a/gremlin-tools/pom.xml
+++ b/gremlin-tools/pom.xml
@@ -6,7 +6,7 @@
     <parent>
         <artifactId>tinkerpop</artifactId>
         <groupId>org.apache.tinkerpop</groupId>
-        <version>3.4.12-SNAPSHOT</version>
+        <version>3.5.1-SNAPSHOT</version>
     </parent>
 
     <artifactId>gremlin-tools</artifactId>
diff --git a/gremlint/.gitignore b/gremlint/.gitignore
new file mode 100644
index 0000000..b476937
--- /dev/null
+++ b/gremlint/.gitignore
@@ -0,0 +1,19 @@
+# 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.
+
+node_modules
+/lib
\ No newline at end of file
diff --git a/gremlint/.prettierrc b/gremlint/.prettierrc
new file mode 100644
index 0000000..a0d1c9a
--- /dev/null
+++ b/gremlint/.prettierrc
@@ -0,0 +1,5 @@
+{
+  "printWidth": 120,
+  "trailingComma": "all",
+  "singleQuote": true
+}
diff --git a/gremlin-python/src/main/jython/LICENSE b/gremlint/LICENSE
similarity index 100%
copy from gremlin-python/src/main/jython/LICENSE
copy to gremlint/LICENSE
diff --git a/gremlint/README.md b/gremlint/README.md
new file mode 100644
index 0000000..005c3eb
--- /dev/null
+++ b/gremlint/README.md
@@ -0,0 +1,141 @@
+<!--
+  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.
+-->
+
+![Gremlint Github Header 1920x1024](https://user-images.githubusercontent.com/25663729/88488788-d5a73700-cf8f-11ea-9adb-03d62c77c1b7.png)
+
+### What is Gremlint?
+
+Gremlint is a code formatter which parses Gremlin queries and rewrites them to adhere to certain styling rules. It does so by parsing the query to an abstract syntax tree, and reprinting it from scratch.
+
+### But why?
+
+- To make Gremlin queries more readable
+- To make your queries more beautiful
+- To act as a "living" style guide
+
+### Install Gremlint as a JavaScript / TypeScript package
+
+Since Gremlint is not yet "published", it has to be installed from its GitHub repo:
+
+```bash
+npm install OyvindSabo/gremlint#master
+```
+
+### Basic example
+
+```typescript
+import { formatQuery } from 'gremlint';
+
+const unformattedQuery = `g.V().has('person', 'name', 'marko').shortestPath().with(ShortestPath.target, __.has('name', 'josh')).with(ShortestPath.distance, 'weight')`;
+
+const formattedQuery = formatQuery(unformattedQuery);
+
+console.log(formattedQuery);
+```
+
+```
+g.V().
+  has('person', 'name', 'marko').
+  shortestPath().
+    with(ShortestPath.target, __.has('name', 'josh')).
+    with(ShortestPath.distance, 'weight')
+```
+
+### Override default max line length
+
+The default max line length is 80, but it can easily be overridden.
+
+```typescript
+import { formatQuery } from 'gremlint';
+
+const unformattedQuery = `g.V().has('person', 'name', 'marko').shortestPath().with(ShortestPath.target, __.has('name', 'josh')).with(ShortestPath.distance, 'weight')`;
+
+const formattedQuery = formatQuery(unformattedQuery, { maxLineLength: 50 });
+
+console.log(formattedQuery);
+```
+
+```
+g.V().
+  has('person', 'name', 'marko').
+  shortestPath().
+    with(
+      ShortestPath.target,
+      __.has('name', 'josh')).
+    with(ShortestPath.distance, 'weight')
+```
+
+### Other formatting options
+
+```typescript
+import { formatQuery } from 'gremlint';
+
+const unformattedQuery = `g.V().has('person', 'name', 'marko').shortestPath().with(ShortestPath.target, __.has('name', 'josh')).with(ShortestPath.distance, 'weight')`;
+
+const formattedQuery = formatQuery(unformattedQuery, {
+  indentation: 4, // default: 0
+  maxLineLength: 40, // default: 80
+  shouldPlaceDotsAfterLineBreaks: true, // default: false
+});
+
+console.log(formattedQuery);
+```
+
+```
+    g.V()
+      .has('person', 'name', 'marko')
+      .shortestPath()
+        .with(
+          ShortestPath.target,
+          __.has('name', 'josh'))
+        .with(
+          ShortestPath.distance,
+          'weight')
+```
+
+### Just looking for an online Gremlin query formatter?
+
+https://gremlint.com is a website which utilizes the Gremlint library to give users an online "living" style guide for Gremlin queries. It also serves as a platform for showcasing the features of Gremlint. Its source code is available [here](https://github.com/apache/tinkerpop/tree/master/docs/site/home/gremlint).
+![Gremlint V2 Screenshot](https://user-images.githubusercontent.com/25663729/88488518-f078ac00-cf8d-11ea-9e1c-01edec285751.png)
+
+### For contributors
+
+**Install dependencies**
+
+`npm install`
+
+**Lint source files**
+
+`npm run lint`
+
+**Format source files**
+
+`npm run format`
+
+**Run tests**
+
+`npm test`
+
+**Compile the TypeScript source code**
+
+`npm run build`
+
+**Bump version**
+
+`npm version [major | minor | patch]`
diff --git a/gremlint/jestconfig.json b/gremlint/jestconfig.json
new file mode 100644
index 0000000..20c25c0
--- /dev/null
+++ b/gremlint/jestconfig.json
@@ -0,0 +1,7 @@
+{
+  "transform": {
+    "^.+\\.(t|j)sx?$": "ts-jest"
+  },
+  "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
+  "moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"]
+}
diff --git a/gremlint/package.json b/gremlint/package.json
new file mode 100644
index 0000000..9ff8f63
--- /dev/null
+++ b/gremlint/package.json
@@ -0,0 +1,48 @@
+{
+  "name": "gremlint",
+  "version": "1.0.0",
+  "description": "Linter/code formatter for Gremlin",
+  "main": "lib/index.js",
+  "types": "lib/index.d.ts",
+  "scripts": {
+    "build": "tsc",
+    "format": "prettier --write \"src/**/*.ts\"",
+    "lint": "tslint -p tsconfig.json",
+    "test": "jest --config jestconfig.json",
+    "prepare": "npm run build",
+    "prepublishOnly": "npm test && npm run lint",
+    "preversion": "npm run lint",
+    "version": "npm run format && git add -A src",
+    "postversion": "git push && git push --tags"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/apache/tinkerpop.git"
+  },
+  "keywords": [
+    "code",
+    "formatter",
+    "graph",
+    "gremlin",
+    "query"
+  ],
+  "author": "Øyvind Sæbø",
+  "license": "Apache-2.0",
+  "bugs": {
+    "url": "https://issues.apache.org/jira/browse/TINKERPOP"
+  },
+  "homepage": "https://tinkerpop.apache.org/",
+  "devDependencies": {
+    "@types/jest": "^26.0.15",
+    "jest": "^26.6.1",
+    "prettier": "^2.1.2",
+    "ts-jest": "^26.4.2",
+    "tslint": "^6.1.3",
+    "tslint-config-prettier": "^1.18.0",
+    "typescript": "^4.0.3"
+  },
+  "files": [
+    "lib/**/*"
+  ],
+  "dependencies": {}
+}
diff --git a/gremlint/src/formatQuery/__tests__/closureIndentation.test.ts b/gremlint/src/formatQuery/__tests__/closureIndentation.test.ts
new file mode 100644
index 0000000..f0aaadf
--- /dev/null
+++ b/gremlint/src/formatQuery/__tests__/closureIndentation.test.ts
@@ -0,0 +1,349 @@
+/*
+ * 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.
+ */
+
+import { formatQuery } from '..';
+
+test('When specifying indentation for a query, the relative indentation within closures should be preserved', () => {
+  // Test that relative indentation is preserved between all the lines within a closure when indentation is 0
+  expect(
+    formatQuery(
+      `g.V().
+has('sell_price').
+has('buy_price').
+project('product', 'profit').
+by('name').
+by{ it.get().value('sell_price') -
+    it.get().value('buy_price') };`,
+      {
+        indentation: 0,
+        maxLineLength: 70,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(`g.V().
+  has('sell_price').
+  has('buy_price').
+  project('product', 'profit').
+    by('name').
+    by{ it.get().value('sell_price') -
+        it.get().value('buy_price') };`);
+
+  // Test that relative indentation is preserved between all the lines within a closure when indentation is 20
+  expect(
+    formatQuery(
+      `g.V().
+has('sell_price').
+has('buy_price').
+project('product', 'profit').
+by('name').
+by{ it.get().value('sell_price') -
+    it.get().value('buy_price') };`,
+      {
+        indentation: 20,
+        maxLineLength: 70,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(`                    g.V().
+                      has('sell_price').
+                      has('buy_price').
+                      project('product', 'profit').
+                        by('name').
+                        by{ it.get().value('sell_price') -
+                            it.get().value('buy_price') };`);
+
+  // Test that relative indentation is preserved in closures which are nested
+  expect(
+    formatQuery(
+      `g.V().filter(out('Sells').
+             map{ it.get('sell_price') -
+                  it.get('buy_price') }.
+             where(gt(50)))`,
+      { indentation: 0, maxLineLength: 45, shouldPlaceDotsAfterLineBreaks: false },
+    ),
+  ).toBe(
+    `g.V().
+  filter(
+    out('Sells').
+    map{ it.get('sell_price') -
+         it.get('buy_price') }.
+    where(gt(50)))`,
+  );
+
+  expect(
+    formatQuery(
+      `g.V().filter(map{ one   = 1
+                  two   = 2
+                  three = 3 }))`,
+      { indentation: 0, maxLineLength: 35, shouldPlaceDotsAfterLineBreaks: false },
+    ),
+  ).toBe(`g.V().filter(map{ one   = 1
+                  two   = 2
+                  three = 3 }))`);
+  expect(
+    formatQuery(
+      `g.V().filter(map{ one   = 1
+                  two   = 2
+                  three = 3 }))`,
+      { indentation: 0, maxLineLength: 28, shouldPlaceDotsAfterLineBreaks: false },
+    ),
+  ).toBe(`g.V().
+  filter(map{ one   = 1
+              two   = 2
+              three = 3 }))`);
+  expect(
+    formatQuery(
+      `g.V().filter(map{ one   = 1
+                  two   = 2
+                  three = 3 }))`,
+      { indentation: 0, maxLineLength: 22, shouldPlaceDotsAfterLineBreaks: false },
+    ),
+  ).toBe(`g.V().
+  filter(
+    map{ one   = 1
+         two   = 2
+         three = 3 }))`);
+
+  expect(
+    formatQuery(
+      `g.V().where(map{ buyPrice  = it.get().value('buy_price');
+                 sellPrice = it.get().value('sell_price');
+                 sellPrice - buyPrice; }.is(gt(50)))`,
+      { indentation: 0, maxLineLength: 60, shouldPlaceDotsAfterLineBreaks: false },
+    ),
+  ).toBe(`g.V().where(map{ buyPrice  = it.get().value('buy_price');
+                 sellPrice = it.get().value('sell_price');
+                 sellPrice - buyPrice; }.is(gt(50)))`);
+  expect(
+    formatQuery(
+      `g.V().where(map{ buyPrice  = it.get().value('buy_price');
+                 sellPrice = it.get().value('sell_price');
+                 sellPrice - buyPrice; }.is(gt(50)))`,
+      { indentation: 0, maxLineLength: 50, shouldPlaceDotsAfterLineBreaks: false },
+    ),
+  ).toBe(`g.V().
+  where(map{ buyPrice  = it.get().value('buy_price');
+             sellPrice = it.get().value('sell_price');
+             sellPrice - buyPrice; }.is(gt(50)))`);
+  expect(
+    formatQuery(
+      `g.V().where(map{ buyPrice  = it.get().value('buy_price');
+                 sellPrice = it.get().value('sell_price');
+                 sellPrice - buyPrice; }.is(gt(50)))`,
+      { indentation: 0, maxLineLength: 45, shouldPlaceDotsAfterLineBreaks: false },
+    ),
+  ).toBe(`g.V().
+  where(
+    map{ buyPrice  = it.get().value('buy_price');
+         sellPrice = it.get().value('sell_price');
+         sellPrice - buyPrice; }.is(gt(50)))`);
+
+  expect(
+    formatQuery(
+      `g.V().where(out().map{ buyPrice  = it.get().value('buy_price');
+                       sellPrice = it.get().value('sell_price');
+                       sellPrice - buyPrice; }.is(gt(50)))`,
+      { indentation: 0, maxLineLength: 60, shouldPlaceDotsAfterLineBreaks: false },
+    ),
+  ).toBe(`g.V().where(out().map{ buyPrice  = it.get().value('buy_price');
+                       sellPrice = it.get().value('sell_price');
+                       sellPrice - buyPrice; }.is(gt(50)))`);
+  expect(
+    formatQuery(
+      `g.V().where(out().map{ buyPrice  = it.get().value('buy_price');
+                       sellPrice = it.get().value('sell_price');
+                       sellPrice - buyPrice; }.is(gt(50)))`,
+      { indentation: 0, maxLineLength: 55, shouldPlaceDotsAfterLineBreaks: false },
+    ),
+  ).toBe(`g.V().
+  where(out().map{ buyPrice  = it.get().value('buy_price');
+                   sellPrice = it.get().value('sell_price');
+                   sellPrice - buyPrice; }.is(gt(50)))`);
+  expect(
+    formatQuery(
+      `g.V().where(out().map{ buyPrice  = it.get().value('buy_price');
+                       sellPrice = it.get().value('sell_price');
+                       sellPrice - buyPrice; }.is(gt(50)))`,
+      { indentation: 0, maxLineLength: 50, shouldPlaceDotsAfterLineBreaks: false },
+    ),
+  ).toBe(`g.V().
+  where(
+    out().map{ buyPrice  = it.get().value('buy_price');
+               sellPrice = it.get().value('sell_price');
+               sellPrice - buyPrice; }.is(gt(50)))`);
+  expect(
+    formatQuery(
+      `g.V().where(out().map{ buyPrice  = it.get().value('buy_price');
+                       sellPrice = it.get().value('sell_price');
+                       sellPrice - buyPrice; }.is(gt(50)))`,
+      { indentation: 0, maxLineLength: 45, shouldPlaceDotsAfterLineBreaks: false },
+    ),
+  ).toBe(`g.V().
+  where(
+    out().
+    map{ buyPrice  = it.get().value('buy_price');
+         sellPrice = it.get().value('sell_price');
+         sellPrice - buyPrice; }.
+    is(gt(50)))`);
+
+  // Test that relative indentation is preserved between all the lines within a closure when not all tokens in a stepGroup are methods (for instance, g in g.V() adds to the width of the stepGroup even if it is not a method)
+  expect(
+    formatQuery(
+      `g.V().map({ it.get('sell_price') -
+            it.get('buy_price') }))`,
+      {
+        indentation: 0,
+        maxLineLength: 35,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(`g.V().map({ it.get('sell_price') -
+            it.get('buy_price') }))`);
+
+  // Test that relative indentation is preserved between all the lines within a closure when the first line is indented because the query doesn't start at the beginning of the line
+  expect(
+    formatQuery(
+      `profit = g.V().map({ it.get('sell_price') -
+                     it.get('buy_price') }))`,
+      {
+        indentation: 0,
+        maxLineLength: 45,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(`profit = g.V().map({ it.get('sell_price') -
+                     it.get('buy_price') }))`);
+
+  // Test that relative indentation is preserved between all lines within a closure when the method to which the closure is an argument is wrapped
+  expect(
+    formatQuery(
+      `g.V(ids).
+  has('factor_a').
+  has('factor_b').
+  project('Factor A', 'Factor B', 'Product').
+    by(values('factor_a')).
+    by(values('factor_b')).
+    by(map{ it.get().value('factor_a') *
+            it.get().value('factor_b') })`,
+      { indentation: 0, maxLineLength: 40, shouldPlaceDotsAfterLineBreaks: false },
+    ),
+  ).toBe(`g.V(ids).
+  has('factor_a').
+  has('factor_b').
+  project(
+    'Factor A',
+    'Factor B',
+    'Product').
+    by(values('factor_a')).
+    by(values('factor_b')).
+    by(
+      map{ it.get().value('factor_a') *
+           it.get().value('factor_b') })`);
+
+  // Test that relative indentation is preserved between all lines within a closure when dots are placed after line breaks
+  // When the whole query is long enough to wrap
+  expect(
+    formatQuery(
+      `g.V(ids).
+  has('factor_a').
+  has('factor_b').
+  project('Factor A', 'Factor B', 'Product').
+    by(values('factor_a')).
+    by(values('factor_b')).
+    by(map{ it.get().value('factor_a') *
+            it.get().value('factor_b') })`,
+      { indentation: 0, maxLineLength: 45, shouldPlaceDotsAfterLineBreaks: true },
+    ),
+  ).toBe(`g.V(ids)
+  .has('factor_a')
+  .has('factor_b')
+  .project('Factor A', 'Factor B', 'Product')
+    .by(values('factor_a'))
+    .by(values('factor_b'))
+    .by(map{ it.get().value('factor_a') *
+             it.get().value('factor_b') })`);
+
+  // When the query is long enough to wrap, but the traversal containing the closure is not the first step in its step group and not long enough to wrap
+  expect(
+    formatQuery(
+      `g.V().where(out().map{ buyPrice  = it.get().value('buy_price');
+                       sellPrice = it.get().value('sell_price');
+                       sellPrice - buyPrice; })`,
+      { indentation: 0, maxLineLength: 50, shouldPlaceDotsAfterLineBreaks: true },
+    ),
+  ).toBe(`g.V().where(out().map{ buyPrice  = it.get().value('buy_price');
+                       sellPrice = it.get().value('sell_price');
+                       sellPrice - buyPrice; })`);
+
+  // When the query is long enough to wrap, but the traversal containing the closure is the first step in its step group and not long enough to wrap
+  expect(
+    formatQuery(
+      `g.V().where(out().map{ buyPrice  = it.get().value('buy_price');
+                       sellPrice = it.get().value('sell_price');
+                       sellPrice - buyPrice; }.is(gt(50)))`,
+      { indentation: 0, maxLineLength: 45, shouldPlaceDotsAfterLineBreaks: true },
+    ),
+  ).toBe(`g.V()
+  .where(
+    out()
+    .map{ buyPrice  = it.get().value('buy_price');
+          sellPrice = it.get().value('sell_price');
+          sellPrice - buyPrice; }
+    .is(gt(50)))`);
+
+  // When the query is long enough to wrap, but the traversal containing the closure is the first step in its traversal and not long enough to wrap
+  expect(
+    formatQuery(
+      `g.V(ids).
+  has('factor_a').
+  has('factor_b').
+  project('Factor A', 'Factor B', 'Product').
+    by(values('factor_a')).
+    by(values('factor_b')).
+    by(map{ it.get().value('factor_a') *
+            it.get().value('factor_b') })`,
+      { indentation: 0, maxLineLength: 40, shouldPlaceDotsAfterLineBreaks: true },
+    ),
+  ).toBe(`g.V(ids)
+  .has('factor_a')
+  .has('factor_b')
+  .project(
+    'Factor A',
+    'Factor B',
+    'Product')
+    .by(values('factor_a'))
+    .by(values('factor_b'))
+    .by(
+      map{ it.get().value('factor_a') *
+           it.get().value('factor_b') })`);
+
+  // When the whole query is short enough to not wrap
+  expect(
+    formatQuery(
+      `g.V().map({ it.get('sell_price') -
+            it.get('buy_price') }))`,
+      {
+        indentation: 0,
+        maxLineLength: 35,
+        shouldPlaceDotsAfterLineBreaks: true,
+      },
+    ),
+  ).toBe(`g.V().map({ it.get('sell_price') -
+            it.get('buy_price') }))`);
+});
diff --git a/gremlint/src/formatQuery/__tests__/curlyBracketMultilineWrapping.test.ts b/gremlint/src/formatQuery/__tests__/curlyBracketMultilineWrapping.test.ts
new file mode 100644
index 0000000..d131748
--- /dev/null
+++ b/gremlint/src/formatQuery/__tests__/curlyBracketMultilineWrapping.test.ts
@@ -0,0 +1,171 @@
+/*
+ * 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.
+ */
+
+import { formatQuery } from '..';
+
+test('When determining if multiline curly bracket closures should cause wrapping, look only at the longest line of the code block', () => {
+  // Test that when moving multiline code blocks, we move all the lines of the code block, not just the first
+  expect(
+    formatQuery(
+      `g.V(1).out().map{ it.get()
+                    .value('name') }`,
+      {
+        indentation: 0,
+        maxLineLength: 25,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(`g.V(1).
+  out().
+  map{ it.get()
+         .value('name') }`);
+
+  expect(
+    formatQuery(
+      `g.V().filter{ it.get()
+                .label() == 'person' }`,
+      {
+        indentation: 0,
+        maxLineLength: 35,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(`g.V().
+  filter{ it.get()
+            .label() == 'person' }`);
+
+  expect(
+    formatQuery(
+      `g.V().
+branch{ it.get()
+          .value('name') }.
+option('marko', values('age')).
+option(none, values('name'))`,
+      {
+        indentation: 0,
+        maxLineLength: 35,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(`g.V().
+  branch{ it.get()
+            .value('name') }.
+    option('marko', values('age')).
+    option(none, values('name'))`);
+
+  expect(
+    formatQuery(
+      `g.V(4).
+out().
+values('name').
+inject('daniel').
+map{ it.get()
+       .length() }.
+path()`,
+      {
+        indentation: 0,
+        maxLineLength: 25,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(`g.V(4).
+  out().
+  values('name').
+  inject('daniel').
+  map{ it.get()
+         .length() }.
+  path()`);
+
+  expect(
+    formatQuery(
+      `g.V().
+filter{ it.get()
+          .value('name') == 'marko' }.
+flatMap{ it.get()
+           .vertices(OUT,'created') }.
+map{ it.get()
+       .value('name') }`,
+      {
+        indentation: 0,
+        maxLineLength: 40,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(`g.V().
+  filter{ it.get()
+            .value('name') == 'marko' }.
+  flatMap{ it.get()
+             .vertices(OUT,'created') }.
+  map{ it.get()
+         .value('name') }`);
+
+  expect(
+    formatQuery(
+      `g.V().
+out().
+out().
+path().
+by{ it.value('name') }.
+by{ it.value('name') }.
+by{ g.V(it).
+      in('created').
+      values('name').
+      fold().next() }`,
+      {
+        indentation: 0,
+        maxLineLength: 30,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(`g.V().
+  out().
+  out().
+  path().
+    by{ it.value('name') }.
+    by{ it.value('name') }.
+    by{ g.V(it).
+          in('created').
+          values('name').
+          fold().next() }`);
+
+  expect(
+    formatQuery(
+      `g.V(ids).
+has('factor_a').
+has('factor_b').
+project('Factor A', 'Factor B', 'Product').
+by(values('factor_a')).
+by(values('factor_b')).
+by(map{ it.get().value('factor_a') * 
+        it.get().value('factor_b') })`,
+      {
+        indentation: 0,
+        maxLineLength: 45,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(`g.V(ids).
+  has('factor_a').
+  has('factor_b').
+  project('Factor A', 'Factor B', 'Product').
+    by(values('factor_a')).
+    by(values('factor_b')).
+    by(map{ it.get().value('factor_a') * 
+            it.get().value('factor_b') })`);
+});
diff --git a/gremlint/src/formatQuery/__tests__/curlyBracketWrapping.test.ts b/gremlint/src/formatQuery/__tests__/curlyBracketWrapping.test.ts
new file mode 100644
index 0000000..49f7f6b
--- /dev/null
+++ b/gremlint/src/formatQuery/__tests__/curlyBracketWrapping.test.ts
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+import { formatQuery } from '..';
+
+test('It should be possible to call curly bracket closures which are not wrapped in parentheses', () => {
+  // Test calling closure whose curly brackets are wrapped in parentheses
+  expect(
+    formatQuery(
+      "g.V().branch({ it.get().value('name') }).option('marko', values('age')).option(none, values('name'))",
+      {
+        indentation: 0,
+        maxLineLength: 40,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(`g.V().
+  branch({ it.get().value('name') }).
+    option('marko', values('age')).
+    option(none, values('name'))`);
+
+  // Test calling closure which is not the last step
+  expect(
+    formatQuery("g.V().branch{ it.get().value('name') }.option('marko', values('age')).option(none, values('name'))", {
+      indentation: 0,
+      maxLineLength: 35,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(`g.V().
+  branch{ it.get().value('name') }.
+    option('marko', values('age')).
+    option(none, values('name'))`);
+  expect(
+    formatQuery("g.V().hasLabel('person').outE('created').count().map{ it.get() * 10 }.path()", {
+      indentation: 0,
+      maxLineLength: 25,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(`g.V().
+  hasLabel('person').
+  outE('created').
+  count().
+  map{ it.get() * 10 }.
+  path()`);
+
+  // Test calling closure which is the last step
+  expect(
+    formatQuery("g.V(4).out().values('name').inject('daniel').map{ it.get().length() }", {
+      indentation: 0,
+      maxLineLength: 30,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(`g.V(4).
+  out().
+  values('name').
+  inject('daniel').
+  map{ it.get().length() }`);
+
+  // Test calling closure whose subsequent step should not wrap
+  expect(
+    formatQuery("g.V(4).out().values('name').inject('daniel').map{ it.get().length() }.path()", {
+      indentation: 0,
+      maxLineLength: 80,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(`g.V(4).out().values('name').inject('daniel').map{ it.get().length() }.path()`);
+
+  // Test calling consecutive closures
+  expect(
+    formatQuery(
+      "g.V().filter{ it.get().value('name') == 'marko' }.flatMap{ it.get().vertices(OUT, 'created') }.map{ it.get().value('name') }",
+      {
+        indentation: 0,
+        maxLineLength: 50,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(`g.V().
+  filter{ it.get().value('name') == 'marko' }.
+  flatMap{ it.get().vertices(OUT, 'created') }.
+  map{ it.get().value('name') }`);
+
+  // Test calling closure by()-modulator
+  expect(
+    formatQuery("g.V().group().by{ it.value('name')[1] }.by('name').next()", {
+      indentation: 0,
+      maxLineLength: 30,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(`g.V().
+  group().
+    by{ it.value('name')[1] }.
+    by('name').
+  next()`);
+});
diff --git a/gremlint/src/formatQuery/__tests__/defaultConfig.test.ts b/gremlint/src/formatQuery/__tests__/defaultConfig.test.ts
new file mode 100644
index 0000000..c6ace66
--- /dev/null
+++ b/gremlint/src/formatQuery/__tests__/defaultConfig.test.ts
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+import { formatQuery } from '..';
+
+test('It should be possible ot use formatQuery with a config, with a partial config and no config', () => {
+  // Test using formatQuery with a default config
+  expect(
+    formatQuery(
+      "g.V().has('person', 'name', 'marko').shortestPath().with(ShortestPath.target, __.has('name', 'josh')).with(ShortestPath.distance, 'weight')",
+      {
+        indentation: 0,
+        maxLineLength: 80,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(`g.V().
+  has('person', 'name', 'marko').
+  shortestPath().
+    with(ShortestPath.target, __.has('name', 'josh')).
+    with(ShortestPath.distance, 'weight')`);
+
+  // Test using formatQuery with a non-default confi
+  expect(
+    formatQuery(
+      "g.V().has('person', 'name', 'marko').shortestPath().with(ShortestPath.target, __.has('name', 'josh')).with(ShortestPath.distance, 'weight')",
+      {
+        indentation: 8,
+        maxLineLength: 50,
+        shouldPlaceDotsAfterLineBreaks: true,
+      },
+    ),
+  ).toBe(`        g.V()
+          .has('person', 'name', 'marko')
+          .shortestPath()
+            .with(
+              ShortestPath.target,
+              __.has('name', 'josh'))
+            .with(ShortestPath.distance, 'weight')`);
+
+  // Test using formatQuery with an empty config
+  expect(
+    formatQuery(
+      "g.V().has('person', 'name', 'marko').shortestPath().with(ShortestPath.target, __.has('name', 'josh')).with(ShortestPath.distance, 'weight')",
+      {},
+    ),
+  ).toBe(`g.V().
+  has('person', 'name', 'marko').
+  shortestPath().
+    with(ShortestPath.target, __.has('name', 'josh')).
+    with(ShortestPath.distance, 'weight')`);
+
+  // Test using formatQuery without a config
+  expect(
+    formatQuery(
+      "g.V().has('person', 'name', 'marko').shortestPath().with(ShortestPath.target, __.has('name', 'josh')).with(ShortestPath.distance, 'weight')",
+    ),
+  ).toBe(`g.V().
+  has('person', 'name', 'marko').
+  shortestPath().
+    with(ShortestPath.target, __.has('name', 'josh')).
+    with(ShortestPath.distance, 'weight')`);
+});
diff --git a/gremlint/src/formatQuery/__tests__/determineWhatPartsOfCodeAreGremlin.test.ts b/gremlint/src/formatQuery/__tests__/determineWhatPartsOfCodeAreGremlin.test.ts
new file mode 100644
index 0000000..3f1a2e6
--- /dev/null
+++ b/gremlint/src/formatQuery/__tests__/determineWhatPartsOfCodeAreGremlin.test.ts
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+
+import { formatQuery } from '..';
+
+test('Extract the parts of the code that can be parsed as Gremlin, format those separately, and leave the rest of the code alone', () => {
+  expect(
+    formatQuery(
+      `contains = {
+  value -> it.get().contains(value)
+}
+
+g.V().filter(values('name').filter(contains('Gremlint')))`,
+      {
+        indentation: 0,
+        maxLineLength: 35,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(`contains = {
+  value -> it.get().contains(value)
+}
+
+g.V().
+  filter(
+    values('name').
+    filter(contains('Gremlint')))`);
+
+  expect(
+    formatQuery(
+      `      g.V(ids).
+     has('factor_a').
+    has('factor_b').
+   project('Factor A', 'Factor B', 'Product').
+  by(values('factor_a')).
+ by(values('factor_b')).
+by(map({ it.get().value('factor_a') *
+         it.get().value('factor_b') }))`,
+      {
+        indentation: 0,
+        maxLineLength: 72,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(`      g.V(ids).
+  has('factor_a').
+  has('factor_b').
+  project('Factor A', 'Factor B', 'Product').
+    by(values('factor_a')).
+    by(values('factor_b')).
+    by(map({ it.get().value('factor_a') *
+             it.get().value('factor_b') }))`);
+
+  expect(
+    formatQuery(
+      `a = 4.5;
+b = 4.5;
+
+g.V(ids).
+has('factor_a').
+has('factor_b').
+project('Factor A', 'Factor B', 'Product').
+by(values('factor_a')).
+by(values('factor_b')).
+by(map{ it.get().value('factor_a') *
+        it.get().value('factor_b') })`,
+      {
+        indentation: 0,
+        maxLineLength: 45,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(`a = 4.5;
+b = 4.5;
+
+g.V(ids).
+  has('factor_a').
+  has('factor_b').
+  project('Factor A', 'Factor B', 'Product').
+    by(values('factor_a')).
+    by(values('factor_b')).
+    by(map{ it.get().value('factor_a') *
+            it.get().value('factor_b') })`);
+
+  expect(
+    formatQuery(
+      `g.V(ids).
+has('factor_a').
+has('factor_b').
+project('Factor A', 'Factor B', 'Product').
+by(values('factor_a')).
+by(values('factor_b')).
+by(map{ it.get().value('factor_a') *
+        it.get().value('factor_b') });`,
+      {
+        indentation: 0,
+        maxLineLength: 45,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(`g.V(ids).
+  has('factor_a').
+  has('factor_b').
+  project('Factor A', 'Factor B', 'Product').
+    by(values('factor_a')).
+    by(values('factor_b')).
+    by(map{ it.get().value('factor_a') *
+            it.get().value('factor_b') });`);
+});
diff --git a/gremlint/src/formatQuery/__tests__/dotsAfterLineBreaks.test.ts b/gremlint/src/formatQuery/__tests__/dotsAfterLineBreaks.test.ts
new file mode 100644
index 0000000..831e1b8
--- /dev/null
+++ b/gremlint/src/formatQuery/__tests__/dotsAfterLineBreaks.test.ts
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+import { formatQuery } from '..';
+
+test('If dots are configured to be placed after line breaks, make sure they are correctly placed, and neither missing nor duplicated', () => {
+  expect(
+    formatQuery(
+      "g.V().hasLabel('person').group().by(values('name', 'age').fold()).unfold().filter(select(values).count(local).is(gt(1)))",
+      {
+        indentation: 0,
+        maxLineLength: 40,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(`g.V().
+  hasLabel('person').
+  group().
+    by(values('name', 'age').fold()).
+  unfold().
+  filter(
+    select(values).
+    count(local).
+    is(gt(1)))`);
+
+  expect(
+    formatQuery(
+      "g.V().hasLabel('person').group().by(values('name', 'age').fold()).unfold().filter(select(values).count(local).is(gt(1)))",
+      {
+        indentation: 0,
+        maxLineLength: 35,
+        shouldPlaceDotsAfterLineBreaks: true,
+      },
+    ),
+  ).toBe(`g.V()
+  .hasLabel('person')
+  .group()
+    .by(
+      values('name', 'age').fold())
+  .unfold()
+  .filter(
+    select(values)
+    .count(local)
+    .is(gt(1)))`);
+});
diff --git a/gremlint/src/formatQuery/__tests__/invalidIndentationAndMaxLineLength.test.ts b/gremlint/src/formatQuery/__tests__/invalidIndentationAndMaxLineLength.test.ts
new file mode 100644
index 0000000..e743a11
--- /dev/null
+++ b/gremlint/src/formatQuery/__tests__/invalidIndentationAndMaxLineLength.test.ts
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+import { formatQuery } from '..';
+
+test('The formatter should not crash when indentation is equal to maxLineLength', () => {
+  expect(
+    formatQuery(`g.V()`, {
+      indentation: 0,
+      maxLineLength: 0,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(`g.V(
+)`);
+});
diff --git a/gremlint/src/formatQuery/__tests__/maxLineLength.test.ts b/gremlint/src/formatQuery/__tests__/maxLineLength.test.ts
new file mode 100644
index 0000000..070fa11
--- /dev/null
+++ b/gremlint/src/formatQuery/__tests__/maxLineLength.test.ts
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+import { formatQuery } from '..';
+
+test('No line in the query should exceed the maximum line length', () => {
+  // When the maximum line length is equal to the length of the query, no line wrapping should occur
+  expect(
+    formatQuery("g.V().hasLabel('person').where(outE('created').count().is(P.gte(2))).count()", {
+      indentation: 0,
+      maxLineLength: 76,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe("g.V().hasLabel('person').where(outE('created').count().is(P.gte(2))).count()");
+
+  // A query of length 77 should be wrapped when the maximum line length is set to 76
+  expect(
+    formatQuery("g.V().hasLabel('person').where(outE('created').count().is(P.gte(2))).count()", {
+      indentation: 0,
+      maxLineLength: 75,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(`g.V().
+  hasLabel('person').
+  where(outE('created').count().is(P.gte(2))).
+  count()`);
+
+  // When wrapping occurs, the parentheses, punctuations or commas after the wrapped tokens should be included when
+  // considering whether to further wrap the query. This doesn't currently work, as the following test shows
+  // https://issues.apache.org/jira/browse/TINKERPOP-2539
+  /*expect(
+    formatQuery("g.V().hasLabel('person').where(outE('created').count().is(P.gte(2))).count()", {
+      indentation: 0,
+      maxLineLength: 45,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(`g.V().
+  hasLabel('person').
+  where(
+    outE('created').count().is(P.gte(2))).
+  count()`);*/
+
+  // Test that if the query is wrapped before exceeding the max line length, even if it does not start at the beginning
+  // of the line
+  expect(
+    formatQuery("List<Vertex> people = g.V().hasLabel('person').toList();", {
+      indentation: 0,
+      maxLineLength: 40,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(`List<Vertex> people = g.V().
+  hasLabel('person').
+  toList();`);
+});
diff --git a/gremlint/src/formatQuery/__tests__/modulatorIndentation.test.ts b/gremlint/src/formatQuery/__tests__/modulatorIndentation.test.ts
new file mode 100644
index 0000000..4ebb342
--- /dev/null
+++ b/gremlint/src/formatQuery/__tests__/modulatorIndentation.test.ts
@@ -0,0 +1,841 @@
+/*
+ * 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.
+ */
+
+import { formatQuery } from '..';
+
+// If modulators have to be wrapped, they should be indented with two additional spaces, but consecutive steps should
+// not be indented with two additional spaces. Check that as-steps are indented as modulators.
+test('Wrapped modulators should be indented with two spaces', () => {
+  // Test as()-modulator indentation
+  expect(
+    formatQuery(
+      "g.V().has('name', within('marko', 'vadas', 'josh')).as('person').V().has('name', within('lop', 'ripple')).addE('uses').from('person')",
+      {
+        indentation: 0,
+        maxLineLength: 50,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(`g.V().
+  has('name', within('marko', 'vadas', 'josh')).
+    as('person').
+  V().
+  has('name', within('lop', 'ripple')).
+  addE('uses').from('person')`);
+
+  // Test as_()-modulator indentation
+  expect(
+    formatQuery(
+      "g.V().has('name', within('marko', 'vadas', 'josh')).as_('person').V().has('name', within('lop', 'ripple')).addE('uses').from('person')",
+      {
+        indentation: 0,
+        maxLineLength: 50,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(`g.V().
+  has('name', within('marko', 'vadas', 'josh')).
+    as_('person').
+  V().
+  has('name', within('lop', 'ripple')).
+  addE('uses').from('person')`);
+
+  // Test by()-modulator indentation
+  expect(
+    formatQuery(
+      "g.V().hasLabel('person').group().by(values('name', 'age').fold()).unfold().filter(select(values).count(local).is(gt(1)))",
+      {
+        indentation: 0,
+        maxLineLength: 40,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(`g.V().
+  hasLabel('person').
+  group().
+    by(values('name', 'age').fold()).
+  unfold().
+  filter(
+    select(values).
+    count(local).
+    is(gt(1)))`);
+  expect(
+    formatQuery(
+      "g.V().hasLabel('person').groupCount().by(values('age').choose(is(lt(28)),constant('young'),choose(is(lt(30)), constant('old'), constant('very old'))))",
+      {
+        indentation: 0,
+        maxLineLength: 80,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(`g.V().
+  hasLabel('person').
+  groupCount().
+    by(
+      values('age').
+      choose(
+        is(lt(28)),
+        constant('young'),
+        choose(is(lt(30)), constant('old'), constant('very old'))))`);
+
+  // Test emit()-modulator indentation
+  expect(
+    formatQuery("g.V(1).repeat(bothE('created').dedup().otherV()).emit().path()", {
+      indentation: 0,
+      maxLineLength: 45,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(
+    `g.V(1).
+  repeat(bothE('created').dedup().otherV()).
+    emit().
+  path()`,
+  );
+  expect(
+    formatQuery('g.V().repeat(both()).times(1000000).emit().range(6,10)', {
+      indentation: 0,
+      maxLineLength: 35,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(
+    `g.V().
+  repeat(both()).
+    times(1000000).
+    emit().
+  range(6, 10)`,
+  );
+  expect(
+    formatQuery("g.V(1).repeat(out()).times(2).emit().path().by('name')", {
+      indentation: 0,
+      maxLineLength: 30,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(
+    `g.V(1).
+  repeat(out()).
+    times(2).
+    emit().
+  path().by('name')`,
+  );
+  expect(
+    formatQuery("g.withSack(1).V(1).repeat(sack(sum).by(constant(1))).times(10).emit().sack().math('sin _')", {
+      indentation: 0,
+      maxLineLength: 40,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(
+    `g.withSack(1).
+  V(1).
+  repeat(sack(sum).by(constant(1))).
+    times(10).
+    emit().
+  sack().
+  math('sin _')`,
+  );
+
+  // Test from()-modulator indentation
+  expect(
+    formatQuery(
+      "g.V().has('person','name','vadas').as('e').in('knows').as('m').out('knows').where(neq('e')).path().from('m').by('name')",
+      {
+        indentation: 0,
+        maxLineLength: 20,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(
+    `g.V().
+  has(
+    'person',
+    'name',
+    'vadas').
+    as('e').
+  in('knows').
+    as('m').
+  out('knows').
+  where(neq('e')).
+  path().
+    from('m').
+    by('name')`,
+  );
+
+  // Test from()-modulator indentation
+  expect(
+    formatQuery(
+      "g.V().has('person','name','vadas').as_('e').in('knows').as_('m').out('knows').where(neq('e')).path().from_('m').by('name')",
+      {
+        indentation: 0,
+        maxLineLength: 20,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(
+    `g.V().
+  has(
+    'person',
+    'name',
+    'vadas').
+    as_('e').
+  in('knows').
+    as_('m').
+  out('knows').
+  where(neq('e')).
+  path().
+    from_('m').
+    by('name')`,
+  );
+
+  // Test option()-modulator indentation
+  expect(
+    formatQuery(
+      "g.V().hasLabel('person').choose(values('name')).option('marko', values('age')).option('josh', values('name')).option('vadas', elementMap()).option('peter', label())",
+      {
+        indentation: 0,
+        maxLineLength: 80,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(
+    `g.V().
+  hasLabel('person').
+  choose(values('name')).
+    option('marko', values('age')).
+    option('josh', values('name')).
+    option('vadas', elementMap()).
+    option('peter', label())`,
+  );
+
+  // Test read()-modulator indentation
+  expect(
+    formatQuery('g.io(someInputFile).read().iterate()', {
+      indentation: 0,
+      maxLineLength: 20,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(
+    `g.io(someInputFile).
+    read().
+  iterate()`,
+  );
+
+  // Test times()-modulator indentation
+  expect(
+    formatQuery("g.V().repeat(both()).times(3).values('age').max()", {
+      indentation: 0,
+      maxLineLength: 20,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(
+    `g.V().
+  repeat(both()).
+    times(3).
+  values('age').
+  max()`,
+  );
+
+  // Test to()-modulator indentation
+  expect(
+    formatQuery("g.V(v1).addE('knows').to(v2).property('weight',0.75).iterate()", {
+      indentation: 0,
+      maxLineLength: 20,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(
+    `g.V(v1).
+  addE('knows').
+    to(v2).
+  property(
+    'weight',
+    0.75).
+  iterate()`,
+  );
+
+  // Test until()-modulator indentation
+  expect(
+    formatQuery(
+      "g.V(6).repeat('a', both('created').simplePath()).emit(repeat('b', both('knows')).until(loops('b').as('b').where(loops('a').as('b'))).hasId(2)).dedup()",
+      {
+        indentation: 0,
+        maxLineLength: 45,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(
+    `g.V(6).
+  repeat('a', both('created').simplePath()).
+    emit(
+      repeat('b', both('knows')).
+        until(
+          loops('b').as('b').
+          where(loops('a').as('b'))).
+      hasId(2)).
+  dedup()`,
+  );
+
+  // Test with()-modulator indentation
+  expect(
+    formatQuery(
+      "g.V().connectedComponent().with(ConnectedComponent.propertyName, 'component').project('name','component').by('name').by('component')",
+      {
+        indentation: 0,
+        maxLineLength: 55,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(
+    `g.V().
+  connectedComponent().
+    with(ConnectedComponent.propertyName, 'component').
+  project('name', 'component').
+    by('name').
+    by('component')`,
+  );
+  expect(
+    formatQuery(
+      "g.V().hasLabel('person').connectedComponent().with(ConnectedComponent.propertyName, 'component').with(ConnectedComponent.edges, outE('knows')).project('name','component').by('name').by('component')",
+      {
+        indentation: 0,
+        maxLineLength: 55,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(
+    `g.V().
+  hasLabel('person').
+  connectedComponent().
+    with(ConnectedComponent.propertyName, 'component').
+    with(ConnectedComponent.edges, outE('knows')).
+  project('name', 'component').
+    by('name').
+    by('component')`,
+  );
+  expect(
+    formatQuery(
+      "g.V().hasLabel('software').values('name').fold().order(Scope.local).index().with(WithOptions.indexer, WithOptions.list).unfold().order().by(__.tail(Scope.local, 1))",
+      {
+        indentation: 0,
+        maxLineLength: 50,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(
+    `g.V().
+  hasLabel('software').
+  values('name').
+  fold().
+  order(Scope.local).
+  index().
+    with(WithOptions.indexer, WithOptions.list).
+  unfold().
+  order().by(__.tail(Scope.local, 1))`,
+  );
+  expect(
+    formatQuery(
+      "g.V().hasLabel('person').values('name').fold().order(Scope.local).index().with(WithOptions.indexer, WithOptions.map)",
+      {
+        indentation: 0,
+        maxLineLength: 50,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(
+    `g.V().
+  hasLabel('person').
+  values('name').
+  fold().
+  order(Scope.local).
+  index().
+    with(WithOptions.indexer, WithOptions.map)`,
+  );
+  expect(
+    formatQuery('g.io(someInputFile).with(IO.reader, IO.graphson).read().iterate()', {
+      indentation: 0,
+      maxLineLength: 35,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(
+    `g.io(someInputFile).
+    with(IO.reader, IO.graphson).
+    read().
+  iterate()`,
+  );
+  expect(
+    formatQuery('g.io(someOutputFile).with(IO.writer,IO.graphml).write().iterate()', {
+      indentation: 0,
+      maxLineLength: 35,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(
+    `g.io(someOutputFile).
+    with(IO.writer, IO.graphml).
+    write().
+  iterate()`,
+  );
+  expect(
+    formatQuery(
+      "g.V().hasLabel('person').pageRank().with(PageRank.edges, __.outE('knows')).with(PageRank.propertyName, 'friendRank').order().by('friendRank',desc).elementMap('name','friendRank')",
+      {
+        indentation: 0,
+        maxLineLength: 50,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(
+    `g.V().
+  hasLabel('person').
+  pageRank().
+    with(PageRank.edges, __.outE('knows')).
+    with(PageRank.propertyName, 'friendRank').
+  order().by('friendRank', desc).
+  elementMap('name', 'friendRank')`,
+  );
+  expect(
+    formatQuery(
+      "g.V().hasLabel('person').peerPressure().with(PeerPressure.propertyName, 'cluster').group().by('cluster').by('name')",
+      {
+        indentation: 0,
+        maxLineLength: 50,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(
+    `g.V().
+  hasLabel('person').
+  peerPressure().
+    with(PeerPressure.propertyName, 'cluster').
+  group().by('cluster').by('name')`,
+  );
+  expect(
+    formatQuery("g.V().shortestPath().with(ShortestPath.target, __.has('name','peter'))", {
+      indentation: 0,
+      maxLineLength: 55,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(
+    `g.V().
+  shortestPath().
+    with(ShortestPath.target, __.has('name', 'peter'))`,
+  );
+  expect(
+    formatQuery(
+      "g.V().shortestPath().with(ShortestPath.edges, Direction.IN).with(ShortestPath.target, __.has('name','josh'))",
+      {
+        indentation: 0,
+        maxLineLength: 55,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(
+    `g.V().
+  shortestPath().
+    with(ShortestPath.edges, Direction.IN).
+    with(ShortestPath.target, __.has('name', 'josh'))`,
+  );
+  expect(
+    formatQuery("g.V().has('person','name','marko').shortestPath().with(ShortestPath.target,__.has('name','josh'))", {
+      indentation: 0,
+      maxLineLength: 55,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(
+    `g.V().
+  has('person', 'name', 'marko').
+  shortestPath().
+    with(ShortestPath.target, __.has('name', 'josh'))`,
+  );
+  expect(
+    formatQuery(
+      "g.V().has('person','name','marko').shortestPath().with(ShortestPath.target, __.has('name','josh')).with(ShortestPath.distance, 'weight')",
+      {
+        indentation: 0,
+        maxLineLength: 55,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(
+    `g.V().
+  has('person', 'name', 'marko').
+  shortestPath().
+    with(ShortestPath.target, __.has('name', 'josh')).
+    with(ShortestPath.distance, 'weight')`,
+  );
+  expect(
+    formatQuery(
+      "g.V().has('person','name','marko').shortestPath().with(ShortestPath.target, __.has('name','josh')).with(ShortestPath.includeEdges, true)",
+      {
+        indentation: 0,
+        maxLineLength: 55,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(
+    `g.V().
+  has('person', 'name', 'marko').
+  shortestPath().
+    with(ShortestPath.target, __.has('name', 'josh')).
+    with(ShortestPath.includeEdges, true)`,
+  );
+  expect(
+    formatQuery(
+      "g.inject(g.withComputer().V().shortestPath().with(ShortestPath.distance, 'weight').with(ShortestPath.includeEdges, true).with(ShortestPath.maxDistance, 1).toList().toArray()).map(unfold().values('name','weight').fold())",
+      {
+        indentation: 0,
+        maxLineLength: 50,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(
+    `g.inject(
+  g.withComputer().
+    V().
+    shortestPath().
+      with(ShortestPath.distance, 'weight').
+      with(ShortestPath.includeEdges, true).
+      with(ShortestPath.maxDistance, 1).
+    toList().
+    toArray()).
+  map(unfold().values('name', 'weight').fold())`,
+  );
+  expect(
+    formatQuery("g.V().hasLabel('person').valueMap().with(WithOptions.tokens)", {
+      indentation: 0,
+      maxLineLength: 35,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(
+    `g.V().
+  hasLabel('person').
+  valueMap().
+    with(WithOptions.tokens)`,
+  );
+  expect(
+    formatQuery("g.V().hasLabel('person').valueMap('name').with(WithOptions.tokens,WithOptions.labels)", {
+      indentation: 0,
+      maxLineLength: 35,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(
+    `g.V().
+  hasLabel('person').
+  valueMap('name').
+    with(
+      WithOptions.tokens,
+      WithOptions.labels)`,
+  );
+  expect(
+    formatQuery(
+      "g.V().hasLabel('person').properties('location').valueMap().with(WithOptions.tokens, WithOptions.values)",
+      {
+        indentation: 0,
+        maxLineLength: 35,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(
+    `g.V().
+  hasLabel('person').
+  properties('location').
+  valueMap().
+    with(
+      WithOptions.tokens,
+      WithOptions.values)`,
+  );
+
+  // Test with_()-modulator indentation
+  expect(
+    formatQuery(
+      "g.V().connectedComponent().with_(ConnectedComponent.propertyName, 'component').project('name','component').by('name').by('component')",
+      {
+        indentation: 0,
+        maxLineLength: 55,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(
+    `g.V().
+  connectedComponent().
+    with_(ConnectedComponent.propertyName, 'component').
+  project('name', 'component').
+    by('name').
+    by('component')`,
+  );
+  expect(
+    formatQuery(
+      "g.V().hasLabel('person').connectedComponent().with_(ConnectedComponent.propertyName, 'component').with_(ConnectedComponent.edges, outE('knows')).project('name','component').by('name').by('component')",
+      {
+        indentation: 0,
+        maxLineLength: 55,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(
+    `g.V().
+  hasLabel('person').
+  connectedComponent().
+    with_(ConnectedComponent.propertyName, 'component').
+    with_(ConnectedComponent.edges, outE('knows')).
+  project('name', 'component').
+    by('name').
+    by('component')`,
+  );
+  expect(
+    formatQuery(
+      "g.V().hasLabel('software').values('name').fold().order(Scope.local).index().with_(WithOptions.indexer, WithOptions.list).unfold().order().by(__.tail(Scope.local, 1))",
+      {
+        indentation: 0,
+        maxLineLength: 50,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(
+    `g.V().
+  hasLabel('software').
+  values('name').
+  fold().
+  order(Scope.local).
+  index().
+    with_(WithOptions.indexer, WithOptions.list).
+  unfold().
+  order().by(__.tail(Scope.local, 1))`,
+  );
+  expect(
+    formatQuery(
+      "g.V().hasLabel('person').values('name').fold().order(Scope.local).index().with_(WithOptions.indexer, WithOptions.map)",
+      {
+        indentation: 0,
+        maxLineLength: 50,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(
+    `g.V().
+  hasLabel('person').
+  values('name').
+  fold().
+  order(Scope.local).
+  index().
+    with_(WithOptions.indexer, WithOptions.map)`,
+  );
+  expect(
+    formatQuery('g.io(someInputFile).with_(IO.reader, IO.graphson).read().iterate()', {
+      indentation: 0,
+      maxLineLength: 35,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(
+    `g.io(someInputFile).
+    with_(IO.reader, IO.graphson).
+    read().
+  iterate()`,
+  );
+  expect(
+    formatQuery('g.io(someOutputFile).with_(IO.writer,IO.graphml).write().iterate()', {
+      indentation: 0,
+      maxLineLength: 35,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(
+    `g.io(someOutputFile).
+    with_(IO.writer, IO.graphml).
+    write().
+  iterate()`,
+  );
+  expect(
+    formatQuery(
+      "g.V().hasLabel('person').pageRank().with_(PageRank.edges, __.outE('knows')).with_(PageRank.propertyName, 'friendRank').order().by('friendRank',desc).elementMap('name','friendRank')",
+      {
+        indentation: 0,
+        maxLineLength: 50,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(
+    `g.V().
+  hasLabel('person').
+  pageRank().
+    with_(PageRank.edges, __.outE('knows')).
+    with_(PageRank.propertyName, 'friendRank').
+  order().by('friendRank', desc).
+  elementMap('name', 'friendRank')`,
+  );
+  expect(
+    formatQuery(
+      "g.V().hasLabel('person').peerPressure().with_(PeerPressure.propertyName, 'cluster').group().by('cluster').by('name')",
+      {
+        indentation: 0,
+        maxLineLength: 50,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(
+    `g.V().
+  hasLabel('person').
+  peerPressure().
+    with_(PeerPressure.propertyName, 'cluster').
+  group().by('cluster').by('name')`,
+  );
+  expect(
+    formatQuery("g.V().shortestPath().with_(ShortestPath.target, __.has('name','peter'))", {
+      indentation: 0,
+      maxLineLength: 55,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(
+    `g.V().
+  shortestPath().
+    with_(ShortestPath.target, __.has('name', 'peter'))`,
+  );
+  expect(
+    formatQuery(
+      "g.V().shortestPath().with_(ShortestPath.edges, Direction.IN).with_(ShortestPath.target, __.has('name','josh'))",
+      {
+        indentation: 0,
+        maxLineLength: 55,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(
+    `g.V().
+  shortestPath().
+    with_(ShortestPath.edges, Direction.IN).
+    with_(ShortestPath.target, __.has('name', 'josh'))`,
+  );
+  expect(
+    formatQuery("g.V().has('person','name','marko').shortestPath().with_(ShortestPath.target,__.has('name','josh'))", {
+      indentation: 0,
+      maxLineLength: 55,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(
+    `g.V().
+  has('person', 'name', 'marko').
+  shortestPath().
+    with_(ShortestPath.target, __.has('name', 'josh'))`,
+  );
+  expect(
+    formatQuery(
+      "g.V().has('person','name','marko').shortestPath().with_(ShortestPath.target, __.has('name','josh')).with_(ShortestPath.distance, 'weight')",
+      {
+        indentation: 0,
+        maxLineLength: 55,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(
+    `g.V().
+  has('person', 'name', 'marko').
+  shortestPath().
+    with_(ShortestPath.target, __.has('name', 'josh')).
+    with_(ShortestPath.distance, 'weight')`,
+  );
+  expect(
+    formatQuery(
+      "g.V().has('person','name','marko').shortestPath().with_(ShortestPath.target, __.has('name','josh')).with_(ShortestPath.includeEdges, true)",
+      {
+        indentation: 0,
+        maxLineLength: 55,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(
+    `g.V().
+  has('person', 'name', 'marko').
+  shortestPath().
+    with_(ShortestPath.target, __.has('name', 'josh')).
+    with_(ShortestPath.includeEdges, true)`,
+  );
+  expect(
+    formatQuery(
+      "g.inject(g.withComputer().V().shortestPath().with_(ShortestPath.distance, 'weight').with_(ShortestPath.includeEdges, true).with_(ShortestPath.maxDistance, 1).toList().toArray()).map(unfold().values('name','weight').fold())",
+      {
+        indentation: 0,
+        maxLineLength: 50,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(
+    `g.inject(
+  g.withComputer().
+    V().
+    shortestPath().
+      with_(ShortestPath.distance, 'weight').
+      with_(ShortestPath.includeEdges, true).
+      with_(ShortestPath.maxDistance, 1).
+    toList().
+    toArray()).
+  map(unfold().values('name', 'weight').fold())`,
+  );
+  expect(
+    formatQuery("g.V().hasLabel('person').valueMap().with_(WithOptions.tokens)", {
+      indentation: 0,
+      maxLineLength: 35,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(
+    `g.V().
+  hasLabel('person').
+  valueMap().
+    with_(WithOptions.tokens)`,
+  );
+  expect(
+    formatQuery("g.V().hasLabel('person').valueMap('name').with_(WithOptions.tokens,WithOptions.labels)", {
+      indentation: 0,
+      maxLineLength: 35,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(
+    `g.V().
+  hasLabel('person').
+  valueMap('name').
+    with_(
+      WithOptions.tokens,
+      WithOptions.labels)`,
+  );
+  expect(
+    formatQuery(
+      "g.V().hasLabel('person').properties('location').valueMap().with_(WithOptions.tokens, WithOptions.values)",
+      {
+        indentation: 0,
+        maxLineLength: 35,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(
+    `g.V().
+  hasLabel('person').
+  properties('location').
+  valueMap().
+    with_(
+      WithOptions.tokens,
+      WithOptions.values)`,
+  );
+
+  // Test write()-modulator indentation
+  expect(
+    formatQuery('g.io(someOutputFile).write().iterate()', {
+      indentation: 0,
+      maxLineLength: 25,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(
+    `g.io(someOutputFile).
+    write().
+  iterate()`,
+  );
+});
diff --git a/gremlint/src/formatQuery/__tests__/modulatorWrapping.test.ts b/gremlint/src/formatQuery/__tests__/modulatorWrapping.test.ts
new file mode 100644
index 0000000..8859eac
--- /dev/null
+++ b/gremlint/src/formatQuery/__tests__/modulatorWrapping.test.ts
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ */
+
+import { formatQuery } from '..';
+
+test("Modulators should not be line-wrapped if they can fit on the line of the step they're modulating", () => {
+  // Test as()-modulator wrapping
+  expect(
+    formatQuery(
+      "g.V().hasLabel('person').as('person').properties('location').as('location').select('person','location').by('name').by(valueMap())",
+      {
+        indentation: 0,
+        maxLineLength: 80,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(`g.V().
+  hasLabel('person').as('person').
+  properties('location').as('location').
+  select('person', 'location').by('name').by(valueMap())`);
+  expect(
+    formatQuery(
+      "g.V().hasLabel('person').as('person').properties('location').as('location').select('person','location').by('name').by(valueMap())",
+      {
+        indentation: 0,
+        maxLineLength: 40,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(`g.V().
+  hasLabel('person').as('person').
+  properties('location').as('location').
+  select('person', 'location').
+    by('name').
+    by(valueMap())`);
+  expect(
+    formatQuery(
+      "g.V().hasLabel('person').as('person').properties('location').as('location').select('person','location').by('name').by(valueMap())",
+      {
+        indentation: 0,
+        maxLineLength: 35,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(`g.V().
+  hasLabel('person').as('person').
+  properties('location').
+    as('location').
+  select('person', 'location').
+    by('name').
+    by(valueMap())`);
+
+  // Test by()-modulator wrapping
+  expect(
+    formatQuery('g.V().group().by().by(bothE().count())', {
+      indentation: 0,
+      maxLineLength: 40,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe('g.V().group().by().by(bothE().count())');
+  expect(
+    formatQuery('g.V().group().by().by(bothE().count())', {
+      indentation: 0,
+      maxLineLength: 35,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(`g.V().
+  group().by().by(bothE().count())`);
+  expect(
+    formatQuery('g.V().group().by().by(bothE().count())', {
+      indentation: 0,
+      maxLineLength: 30,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(`g.V().
+  group().
+    by().
+    by(bothE().count())`);
+  expect(
+    formatQuery(
+      "g.V().hasLabel('person').group().by(values('name', 'age').fold()).unfold().filter(select(values).count(local).is(gt(1)))",
+      {
+        indentation: 0,
+        maxLineLength: 45,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(`g.V().
+  hasLabel('person').
+  group().by(values('name', 'age').fold()).
+  unfold().
+  filter(
+    select(values).count(local).is(gt(1)))`);
+  expect(
+    formatQuery(
+      "g.V().hasLabel('person').group().by(values('name', 'age').fold()).unfold().filter(select(values).count(local).is(gt(1)))",
+      {
+        indentation: 0,
+        maxLineLength: 40,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(`g.V().
+  hasLabel('person').
+  group().
+    by(values('name', 'age').fold()).
+  unfold().
+  filter(
+    select(values).
+    count(local).
+    is(gt(1)))`);
+});
diff --git a/gremlint/src/formatQuery/__tests__/multipleQueriesAtOnce.test.ts b/gremlint/src/formatQuery/__tests__/multipleQueriesAtOnce.test.ts
new file mode 100644
index 0000000..bfb8fda
--- /dev/null
+++ b/gremlint/src/formatQuery/__tests__/multipleQueriesAtOnce.test.ts
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+import { formatQuery } from '..';
+
+test('Each of multiple queries formatted at once should be formatted as if they were formatted individually', () => {
+  // Test that linebreaks don't happen too soon because the formatter fails to distinguish between lines from the end
+  // of one query and the start of the next
+  expect(
+    formatQuery(
+      `g.V(1).out().values('name')
+
+g.V(1).out().map{ it.get().value('name') }
+
+g.V(1).out().map(values('name'))`,
+      {
+        indentation: 0,
+        maxLineLength: 45,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(`g.V(1).out().values('name')
+
+g.V(1).out().map{ it.get().value('name') }
+
+g.V(1).out().map(values('name'))`);
+
+  expect(
+    formatQuery(
+      `g.V().branch{ it.get().value('name') }.option('marko', values('age')).option(none, values('name'))
+
+g.V().branch(values('name')).option('marko', values('age')).option(none, values('name'))
+
+g.V().choose(has('name','marko'),values('age'), values('name'))`,
+      {
+        indentation: 0,
+        maxLineLength: 70,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(`g.V().
+  branch{ it.get().value('name') }.
+    option('marko', values('age')).
+    option(none, values('name'))
+
+g.V().
+  branch(values('name')).
+    option('marko', values('age')).
+    option(none, values('name'))
+
+g.V().choose(has('name', 'marko'), values('age'), values('name'))`);
+});
diff --git a/gremlint/src/formatQuery/__tests__/nonGremlinIndentation.test.ts b/gremlint/src/formatQuery/__tests__/nonGremlinIndentation.test.ts
new file mode 100644
index 0000000..88c3f2a
--- /dev/null
+++ b/gremlint/src/formatQuery/__tests__/nonGremlinIndentation.test.ts
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+import { formatQuery } from '..';
+
+// TODO: These tests seem related to those in closureIndentation.test.ts, so it might be worth checking if they can be merged.
+test('Both top-level and inlined non-Gremlin code should be indented together with the Gremlin query', () => {
+  // Test that top-level and inlined non-Gremlin code are not indented when indentation is 0
+  expect(
+    formatQuery(
+      `hasField = { field -> __.has(field) }
+
+profitQuery = g.V().
+filter(hasField('sell_price')).
+filter(hasField('buy_price')).
+project('product', 'profit').
+by('name').
+by{ it.get().value('sell_price') -
+    it.get().value('buy_price') };`,
+      {
+        indentation: 0,
+        maxLineLength: 70,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(`hasField = { field -> __.has(field) }
+
+profitQuery = g.V().
+  filter(hasField('sell_price')).
+  filter(hasField('buy_price')).
+  project('product', 'profit').
+    by('name').
+    by{ it.get().value('sell_price') -
+        it.get().value('buy_price') };`);
+
+  // Test that top-level and inlined non-Gremlin code are not indented when indentation is 20
+  expect(
+    formatQuery(
+      `hasField = { field -> __.has(field) }
+      
+profitQuery = g.V().
+filter(hasField('sell_price')).
+filter(hasField('buy_price')).
+project('product', 'profit').
+by('name').
+by{ it.get().value('sell_price') -
+    it.get().value('buy_price') };`,
+      {
+        indentation: 20,
+        maxLineLength: 70,
+        shouldPlaceDotsAfterLineBreaks: false,
+      },
+    ),
+  ).toBe(`                    hasField = { field -> __.has(field) }
+
+                    profitQuery = g.V().
+                      filter(hasField('sell_price')).
+                      filter(hasField('buy_price')).
+                      project('product', 'profit').
+                        by('name').
+                        by{ it.get().value('sell_price') -
+                            it.get().value('buy_price') };`);
+});
diff --git a/gremlint/src/formatQuery/__tests__/nonMethodIndentation.test.ts b/gremlint/src/formatQuery/__tests__/nonMethodIndentation.test.ts
new file mode 100644
index 0000000..2b2903a
--- /dev/null
+++ b/gremlint/src/formatQuery/__tests__/nonMethodIndentation.test.ts
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+import { formatQuery } from '..';
+
+test('Non-methods in a traversal should be indented correctly, even if this might never occur in a valid query', () => {
+  expect(
+    formatQuery('g.V().stepWhichIsNotAMethod.stepWhichIsAMethod()', {
+      indentation: 0,
+      maxLineLength: 45,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(`g.V().
+  stepWhichIsNotAMethod.stepWhichIsAMethod()`);
+
+  expect(
+    formatQuery('g.V().stepWhichIsNotAMethod', {
+      indentation: 0,
+      maxLineLength: 25,
+      shouldPlaceDotsAfterLineBreaks: false,
+    }),
+  ).toBe(`g.V().
+  stepWhichIsNotAMethod`);
+});
diff --git a/gremlint/src/formatQuery/consts.ts b/gremlint/src/formatQuery/consts.ts
new file mode 100644
index 0000000..6799877
--- /dev/null
+++ b/gremlint/src/formatQuery/consts.ts
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+export const STEP_MODULATORS = [
+  'as',
+  'as_',
+  'by',
+  'emit',
+  'option',
+  'from',
+  'from_',
+  'to',
+  'read',
+  'times',
+  'until',
+  'with',
+  'with_',
+  'write',
+];
diff --git a/gremlint/src/formatQuery/formatSyntaxTrees/formatClosure.ts b/gremlint/src/formatQuery/formatSyntaxTrees/formatClosure.ts
new file mode 100644
index 0000000..9bfd023
--- /dev/null
+++ b/gremlint/src/formatQuery/formatSyntaxTrees/formatClosure.ts
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+import recreateQueryOnelinerFromSyntaxTree from '../recreateQueryOnelinerFromSyntaxTree';
+import {
+  FormattedClosureSyntaxTree,
+  GremlinSyntaxTreeFormatter,
+  GremlintInternalConfig,
+  TokenType,
+  UnformattedClosureCodeBlock,
+  UnformattedClosureLineOfCode,
+  UnformattedClosureSyntaxTree,
+} from '../types';
+import { withNoEndDotInfo } from './utils';
+
+const getClosureLineOfCodeIndentation = (
+  relativeIndentation: number,
+  horizontalPosition: number,
+  methodWidth: number,
+  lineNumber: number,
+) => {
+  if (lineNumber === 0) return Math.max(relativeIndentation, 0);
+  return Math.max(relativeIndentation + horizontalPosition + methodWidth + 1, 0);
+};
+
+const getFormattedClosureLineOfCode = (horizontalPosition: number, methodWidth: number) => (
+  { lineOfCode, relativeIndentation }: UnformattedClosureLineOfCode,
+  lineNumber: number,
+) => ({
+  lineOfCode,
+  relativeIndentation,
+  localIndentation: getClosureLineOfCodeIndentation(relativeIndentation, horizontalPosition, methodWidth, lineNumber),
+});
+
+const getFormattedClosureCodeBlock = (
+  unformattedClosureCodeBlock: UnformattedClosureCodeBlock,
+  horizontalPosition: number,
+  methodWidth: number,
+) => {
+  return unformattedClosureCodeBlock.map(getFormattedClosureLineOfCode(horizontalPosition, methodWidth));
+};
+
+export const formatClosure = (formatSyntaxTree: GremlinSyntaxTreeFormatter) => (config: GremlintInternalConfig) => (
+  syntaxTree: UnformattedClosureSyntaxTree,
+): FormattedClosureSyntaxTree => {
+  const { closureCodeBlock: unformattedClosureCodeBlock, method: unformattedMethod } = syntaxTree;
+  const { localIndentation, horizontalPosition, maxLineLength, shouldEndWithDot } = config;
+  const recreatedQuery = recreateQueryOnelinerFromSyntaxTree(localIndentation)(syntaxTree);
+  const formattedMethod = formatSyntaxTree(withNoEndDotInfo(config))(unformattedMethod);
+  const methodWidth = formattedMethod.width;
+
+  if (recreatedQuery.length <= maxLineLength) {
+    return {
+      type: TokenType.Closure,
+      method: formattedMethod,
+      closureCodeBlock: getFormattedClosureCodeBlock(unformattedClosureCodeBlock, horizontalPosition, methodWidth),
+      localIndentation,
+      width: recreatedQuery.trim().length,
+      shouldStartWithDot: false,
+      shouldEndWithDot: Boolean(shouldEndWithDot),
+    };
+  }
+
+  return {
+    type: TokenType.Closure,
+    method: formattedMethod,
+    closureCodeBlock: getFormattedClosureCodeBlock(unformattedClosureCodeBlock, horizontalPosition, methodWidth),
+    localIndentation: 0,
+    width: 0,
+    shouldStartWithDot: false,
+    shouldEndWithDot: Boolean(shouldEndWithDot),
+  };
+};
diff --git a/gremlint/src/formatQuery/formatSyntaxTrees/formatMethod.ts b/gremlint/src/formatQuery/formatSyntaxTrees/formatMethod.ts
new file mode 100644
index 0000000..fd4f92b
--- /dev/null
+++ b/gremlint/src/formatQuery/formatSyntaxTrees/formatMethod.ts
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+
+import recreateQueryOnelinerFromSyntaxTree from '../recreateQueryOnelinerFromSyntaxTree';
+import {
+  FormattedMethodSyntaxTree,
+  FormattedSyntaxTree,
+  GremlinSyntaxTreeFormatter,
+  GremlintInternalConfig,
+  TokenType,
+  UnformattedMethodSyntaxTree,
+} from '../types';
+import { last, pipe, sum } from '../utils';
+import {
+  withHorizontalPosition,
+  withIncreasedHorizontalPosition,
+  withIncreasedIndentation,
+  withNoEndDotInfo,
+  withZeroDotInfo,
+  withZeroIndentation,
+} from './utils';
+
+// Groups arguments into argument groups an adds a localIndentation property
+export const formatMethod = (formatSyntaxTree: GremlinSyntaxTreeFormatter) => (config: GremlintInternalConfig) => (
+  syntaxTree: UnformattedMethodSyntaxTree,
+): FormattedMethodSyntaxTree => {
+  const recreatedQuery = recreateQueryOnelinerFromSyntaxTree(config.localIndentation)(syntaxTree);
+  const method = formatSyntaxTree(withNoEndDotInfo(config))(syntaxTree.method);
+  const argumentsWillNotBeWrapped = recreatedQuery.length <= config.maxLineLength;
+  if (argumentsWillNotBeWrapped) {
+    return {
+      type: TokenType.Method,
+      method,
+      // The arguments property is here so that the resulted syntax tree can
+      // still be understood by recreateQueryOnelinerFromSyntaxTree
+      arguments: syntaxTree.arguments,
+      argumentGroups: [
+        syntaxTree.arguments.reduce((argumentGroup: FormattedSyntaxTree[], syntaxTree) => {
+          return [
+            ...argumentGroup,
+            formatSyntaxTree(
+              // Since the method's arguments will be on the same line, their horizontal position is increased by the
+              // method's width plus the width of the opening parenthesis
+              pipe(
+                withZeroIndentation,
+                withZeroDotInfo,
+                withIncreasedHorizontalPosition(
+                  method.width + 1 + argumentGroup.map(({ width }) => width).reduce(sum, 0) + argumentGroup.length,
+                ),
+              )(config),
+            )(syntaxTree),
+          ];
+        }, []),
+      ],
+      argumentsShouldStartOnNewLine: false,
+      localIndentation: config.localIndentation,
+      shouldStartWithDot: false,
+      shouldEndWithDot: Boolean(config.shouldEndWithDot),
+      width: recreatedQuery.trim().length,
+    };
+  }
+  // shouldEndWithDot has to reside on the method object, so the end dot can be
+  // placed after the method parentheses. shouldStartWithDot has to be passed on
+  // further down so the start dot can be placed after the indentation.
+  const argumentGroups = syntaxTree.arguments.map((step) => [
+    formatSyntaxTree(
+      pipe(withIncreasedIndentation(2), withZeroDotInfo, withHorizontalPosition(config.localIndentation + 2))(config),
+    )(step),
+  ]);
+  const lastArgumentGroup = last(argumentGroups);
+  // Add the width of the last line of parameters, the dots between them and the indentation of the parameters
+  const width = lastArgumentGroup
+    ? lastArgumentGroup.map(({ width }) => width).reduce(sum, 0) + lastArgumentGroup.length - 1
+    : 0;
+  return {
+    type: TokenType.Method,
+    method,
+    arguments: syntaxTree.arguments,
+    argumentGroups,
+    argumentsShouldStartOnNewLine: true,
+    shouldStartWithDot: false,
+    shouldEndWithDot: Boolean(config.shouldEndWithDot),
+    localIndentation: 0,
+    width,
+  };
+};
diff --git a/gremlint/src/formatQuery/formatSyntaxTrees/formatNonGremlin.ts b/gremlint/src/formatQuery/formatSyntaxTrees/formatNonGremlin.ts
new file mode 100644
index 0000000..94caf85
--- /dev/null
+++ b/gremlint/src/formatQuery/formatSyntaxTrees/formatNonGremlin.ts
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+import { FormattedNonGremlinSyntaxTree, GremlintInternalConfig, UnformattedNonGremlinSyntaxTree } from '../types';
+import { count, last } from '../utils';
+
+export const formatNonGremlin = (_config: GremlintInternalConfig) => (
+  syntaxTree: UnformattedNonGremlinSyntaxTree,
+): FormattedNonGremlinSyntaxTree => {
+  return {
+    ...syntaxTree,
+    width: count(last(syntaxTree.code.split('\n'))),
+  };
+};
diff --git a/gremlint/src/formatQuery/formatSyntaxTrees/formatString.ts b/gremlint/src/formatQuery/formatSyntaxTrees/formatString.ts
new file mode 100644
index 0000000..19660cd
--- /dev/null
+++ b/gremlint/src/formatQuery/formatSyntaxTrees/formatString.ts
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+import { FormattedStringSyntaxTree, GremlintInternalConfig, TokenType, UnformattedStringSyntaxTree } from '../types';
+
+export const formatString = (config: GremlintInternalConfig) => (
+  syntaxTree: UnformattedStringSyntaxTree,
+): FormattedStringSyntaxTree => {
+  return {
+    type: TokenType.String,
+    string: syntaxTree.string,
+    localIndentation: config.localIndentation,
+    width: syntaxTree.string.length + 2,
+  };
+};
diff --git a/gremlint/src/formatQuery/formatSyntaxTrees/formatTraversal/getStepGroups/index.ts b/gremlint/src/formatQuery/formatSyntaxTrees/formatTraversal/getStepGroups/index.ts
new file mode 100644
index 0000000..bfc657c
--- /dev/null
+++ b/gremlint/src/formatQuery/formatSyntaxTrees/formatTraversal/getStepGroups/index.ts
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+import reduceSingleStepInStepGroup from './reduceSingleStepInStepGroup';
+import reduceLastStepInStepGroup from './reduceLastStepInStepGroup';
+import reduceFirstStepInStepGroup from './reduceFirstStepInStepGroup';
+import reduceMiddleStepInStepGroup from './reduceMiddleStepInStepGroup';
+import { isStepFirstStepInStepGroup, shouldStepBeLastStepInStepGroup } from './utils';
+import { choose } from '../../../utils';
+import {
+  GremlinStepGroup,
+  FormattedSyntaxTree,
+  GremlinSyntaxTreeFormatter,
+  GremlintInternalConfig,
+  UnformattedSyntaxTree,
+} from '../../../types';
+
+export const getStepGroups = (
+  formatSyntaxTree: GremlinSyntaxTreeFormatter,
+  steps: UnformattedSyntaxTree[],
+  config: GremlintInternalConfig,
+): GremlinStepGroup[] => {
+  return steps.reduce(
+    choose(
+      shouldStepBeLastStepInStepGroup(config),
+      choose(
+        isStepFirstStepInStepGroup,
+        reduceSingleStepInStepGroup(formatSyntaxTree, config),
+        reduceLastStepInStepGroup(formatSyntaxTree, config),
+      ),
+      choose(
+        isStepFirstStepInStepGroup,
+        reduceFirstStepInStepGroup(formatSyntaxTree, config),
+        reduceMiddleStepInStepGroup(formatSyntaxTree, config),
+      ),
+    ),
+    {
+      stepsInStepGroup: [] as FormattedSyntaxTree[],
+      stepGroups: [] as GremlinStepGroup[],
+    },
+  ).stepGroups;
+};
diff --git a/gremlint/src/formatQuery/formatSyntaxTrees/formatTraversal/getStepGroups/reduceFirstStepInStepGroup.ts b/gremlint/src/formatQuery/formatSyntaxTrees/formatTraversal/getStepGroups/reduceFirstStepInStepGroup.ts
new file mode 100644
index 0000000..0b6601d
--- /dev/null
+++ b/gremlint/src/formatQuery/formatSyntaxTrees/formatTraversal/getStepGroups/reduceFirstStepInStepGroup.ts
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+import {
+  FormattedSyntaxTree,
+  GremlinStepGroup,
+  GremlinSyntaxTreeFormatter,
+  GremlintInternalConfig,
+  UnformattedSyntaxTree,
+} from '../../../types';
+import { pipe } from '../../../utils';
+import { withDotInfo, withHorizontalPosition, withIndentation } from '../../utils';
+import { isTraversalSource } from './utils';
+
+// If it is the first step in a group and also not the last one, format it
+// with indentation, otherwise, remove the indentation
+const reduceFirstStepInStepGroup = (formatSyntaxTree: GremlinSyntaxTreeFormatter, config: GremlintInternalConfig) => (
+  {
+    stepsInStepGroup,
+    stepGroups,
+  }: {
+    stepsInStepGroup: FormattedSyntaxTree[];
+    stepGroups: GremlinStepGroup[];
+  },
+  step: UnformattedSyntaxTree,
+) => {
+  const localIndentation =
+    config.localIndentation + (stepGroups[0] && isTraversalSource(stepGroups[0].steps[0]) ? 2 : 0);
+
+  const isFirstStepGroup = stepGroups.length === 0;
+
+  // It is the first step in a group and should start with a dot if it is
+  // not the first stepGroup and config.shouldPlaceDotsAfterLineBreaks
+  const shouldStartWithDot = !isFirstStepGroup && config.shouldPlaceDotsAfterLineBreaks;
+
+  // It is the first step in a group, but not the last, so it should not
+  // end with a dot.
+  const shouldEndWithDot = false;
+
+  return {
+    stepsInStepGroup: [
+      formatSyntaxTree(
+        pipe(
+          withIndentation(localIndentation),
+          withDotInfo({ shouldStartWithDot, shouldEndWithDot }),
+          withHorizontalPosition(localIndentation),
+        )(config),
+      )(step),
+    ],
+    stepGroups,
+  };
+};
+
+export default reduceFirstStepInStepGroup;
diff --git a/gremlint/src/formatQuery/formatSyntaxTrees/formatTraversal/getStepGroups/reduceLastStepInStepGroup.ts b/gremlint/src/formatQuery/formatSyntaxTrees/formatTraversal/getStepGroups/reduceLastStepInStepGroup.ts
new file mode 100644
index 0000000..1caefdc
--- /dev/null
+++ b/gremlint/src/formatQuery/formatSyntaxTrees/formatTraversal/getStepGroups/reduceLastStepInStepGroup.ts
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+import {
+  FormattedSyntaxTree,
+  GremlinStepGroup,
+  GremlinSyntaxTreeFormatter,
+  GremlintInternalConfig,
+  UnformattedSyntaxTree,
+} from '../../../types';
+import { pipe, sum } from '../../../utils';
+import { withDotInfo, withIncreasedHorizontalPosition, withZeroIndentation } from '../../utils';
+
+// If it should be the last step in a line
+// We don't want to newline after words which are not methods. For
+// instance, g.V() should be one one line, as should __.as
+const reduceLastStepInStepGroup = (formatSyntaxTree: GremlinSyntaxTreeFormatter, config: GremlintInternalConfig) => (
+  {
+    stepsInStepGroup,
+    stepGroups,
+  }: {
+    stepsInStepGroup: FormattedSyntaxTree[];
+    stepGroups: GremlinStepGroup[];
+  },
+  step: UnformattedSyntaxTree,
+  index: number,
+  steps: UnformattedSyntaxTree[],
+) => {
+  const isLastStepGroup = index === steps.length - 1;
+  // If it is the last (and also not first) step in a group
+  // This is not the first step in the step group, so it should not
+  // start with a dot
+  const shouldStartWithDot = false;
+
+  const shouldEndWithDot = !isLastStepGroup && !config.shouldPlaceDotsAfterLineBreaks;
+
+  return {
+    stepsInStepGroup: [],
+    stepGroups: [
+      ...stepGroups,
+      {
+        steps: [
+          ...stepsInStepGroup,
+          formatSyntaxTree(
+            pipe(
+              withZeroIndentation,
+              withDotInfo({ shouldStartWithDot, shouldEndWithDot }),
+              withIncreasedHorizontalPosition(
+                // If I recall correctly, the + stepsInStepGroup.length handles the horizontal increase caused by the dots joining the steps
+                stepsInStepGroup.map(({ width }) => width).reduce(sum, 0) + stepsInStepGroup.length,
+              ),
+            )(config),
+          )(step),
+        ],
+      },
+    ],
+  };
+};
+
+export default reduceLastStepInStepGroup;
diff --git a/gremlint/src/formatQuery/formatSyntaxTrees/formatTraversal/getStepGroups/reduceMiddleStepInStepGroup.ts b/gremlint/src/formatQuery/formatSyntaxTrees/formatTraversal/getStepGroups/reduceMiddleStepInStepGroup.ts
new file mode 100644
index 0000000..6d2059e
--- /dev/null
+++ b/gremlint/src/formatQuery/formatSyntaxTrees/formatTraversal/getStepGroups/reduceMiddleStepInStepGroup.ts
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+import {
+  FormattedSyntaxTree,
+  GremlinStepGroup,
+  GremlinSyntaxTreeFormatter,
+  GremlintInternalConfig,
+  UnformattedSyntaxTree,
+} from '../../../types';
+import { pipe, sum } from '../../../utils';
+import { withDotInfo, withHorizontalPosition, withZeroIndentation } from '../../utils';
+
+const reduceMiddleStepInStepGroup = (formatSyntaxTree: GremlinSyntaxTreeFormatter, config: GremlintInternalConfig) => (
+  {
+    stepsInStepGroup,
+    stepGroups,
+  }: {
+    stepsInStepGroup: FormattedSyntaxTree[];
+    stepGroups: GremlinStepGroup[];
+  },
+  step: UnformattedSyntaxTree,
+) => {
+  const horizontalPosition =
+    config.localIndentation + stepsInStepGroup.map(({ width }) => width).reduce(sum, 0) + stepsInStepGroup.length;
+
+  return {
+    stepsInStepGroup: [
+      ...stepsInStepGroup,
+      formatSyntaxTree(
+        pipe(
+          withZeroIndentation,
+          withDotInfo({ shouldStartWithDot: false, shouldEndWithDot: false }),
+          withHorizontalPosition(horizontalPosition),
+        )(config),
+      )(step),
+    ],
+    stepGroups,
+  };
+};
+
+export default reduceMiddleStepInStepGroup;
diff --git a/gremlint/src/formatQuery/formatSyntaxTrees/formatTraversal/getStepGroups/reduceSingleStepInStepGroup.ts b/gremlint/src/formatQuery/formatSyntaxTrees/formatTraversal/getStepGroups/reduceSingleStepInStepGroup.ts
new file mode 100644
index 0000000..4b90fe7
--- /dev/null
+++ b/gremlint/src/formatQuery/formatSyntaxTrees/formatTraversal/getStepGroups/reduceSingleStepInStepGroup.ts
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+import {
+  FormattedSyntaxTree,
+  GremlinStepGroup,
+  GremlinSyntaxTreeFormatter,
+  GremlintInternalConfig,
+  UnformattedSyntaxTree,
+} from '../../../types';
+import { pipe } from '../../../utils';
+import { withDotInfo, withHorizontalPosition, withIndentation } from '../../utils';
+import { isModulator, isTraversalSource } from './utils';
+
+// If it should be the last step in a line
+// We don't want to newline after words which are not methods. For
+// instance, g.V() should be one one line, as should __.as
+const reduceSingleStepInStepGroup = (formatSyntaxTree: GremlinSyntaxTreeFormatter, config: GremlintInternalConfig) => (
+  {
+    stepsInStepGroup,
+    stepGroups,
+  }: {
+    stepsInStepGroup: FormattedSyntaxTree[];
+    stepGroups: GremlinStepGroup[];
+  },
+  step: UnformattedSyntaxTree,
+  index: number,
+  steps: UnformattedSyntaxTree[],
+) => {
+  const isFirstStepGroup = stepGroups.length === 0;
+  const isLastStepGroup = index === steps.length - 1;
+  const traversalSourceIndentationIncrease = stepGroups[0] && isTraversalSource(stepGroups[0].steps[0]) ? 2 : 0;
+  const modulatorIndentationIncrease = isModulator(step) ? 2 : 0;
+  const localIndentation = config.localIndentation + traversalSourceIndentationIncrease + modulatorIndentationIncrease;
+
+  // This is the only step in the step group, so it is the first step in
+  // the step group. It should only start with a dot if it is not the
+  // first stepGroup and config.shouldPlaceDotsAfterLineBreaks
+  const shouldStartWithDot = !isFirstStepGroup && config.shouldPlaceDotsAfterLineBreaks;
+
+  // It is the last step in a group and should only end with dot if not
+  // config.shouldPlaceDotsAfterLineBreaks this is not the last step in
+  // steps
+  const shouldEndWithDot = !isLastStepGroup && !config.shouldPlaceDotsAfterLineBreaks;
+
+  return {
+    stepsInStepGroup: [],
+    stepGroups: [
+      ...stepGroups,
+      {
+        steps: [
+          formatSyntaxTree(
+            pipe(
+              withIndentation(localIndentation),
+              withDotInfo({ shouldStartWithDot, shouldEndWithDot }),
+              withHorizontalPosition(localIndentation + +config.shouldPlaceDotsAfterLineBreaks),
+            )(config),
+          )(step),
+        ],
+      },
+    ],
+  };
+};
+
+export default reduceSingleStepInStepGroup;
diff --git a/gremlint/src/formatQuery/formatSyntaxTrees/formatTraversal/getStepGroups/utils.ts b/gremlint/src/formatQuery/formatSyntaxTrees/formatTraversal/getStepGroups/utils.ts
new file mode 100644
index 0000000..13392fb
--- /dev/null
+++ b/gremlint/src/formatQuery/formatSyntaxTrees/formatTraversal/getStepGroups/utils.ts
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ */
+
+import {
+  FormattedSyntaxTree,
+  GremlinStepGroup,
+  GremlintInternalConfig,
+  TokenType,
+  UnformattedSyntaxTree,
+} from '../../../types';
+import { STEP_MODULATORS } from '../../../consts';
+import recreateQueryOnelinerFromSyntaxTree from '../../../recreateQueryOnelinerFromSyntaxTree';
+
+export const isTraversalSource = (step: UnformattedSyntaxTree | FormattedSyntaxTree): boolean => {
+  return step.type === TokenType.Word && step.word === 'g';
+};
+
+export const isModulator = (step: UnformattedSyntaxTree | FormattedSyntaxTree): boolean => {
+  if (step.type !== TokenType.Method && step.type !== TokenType.Closure) return false;
+  if (step.method.type !== TokenType.Word) return false;
+  return STEP_MODULATORS.includes(step.method.word);
+};
+
+export const isStepFirstStepInStepGroup = ({ stepsInStepGroup }: { stepsInStepGroup: FormattedSyntaxTree[] }) => {
+  return !stepsInStepGroup.length;
+};
+
+const isLineTooLongWithSubsequentModulators = (config: GremlintInternalConfig) => (
+  {
+    stepsInStepGroup,
+    stepGroups,
+  }: {
+    stepsInStepGroup: FormattedSyntaxTree[];
+    stepGroups: GremlinStepGroup[];
+  },
+  step: UnformattedSyntaxTree,
+  index: number,
+  steps: UnformattedSyntaxTree[],
+) => {
+  const stepsWithSubsequentModulators = steps.slice(index + 1).reduce(
+    (aggregator, step) => {
+      const { stepsInStepGroup, hasReachedFinalModulator } = aggregator;
+      if (hasReachedFinalModulator) return aggregator;
+      if (isModulator(step)) {
+        return {
+          ...aggregator,
+          stepsInStepGroup: [...stepsInStepGroup, step],
+        };
+      }
+      return { ...aggregator, hasReachedFinalModulator: true };
+    },
+    {
+      stepsInStepGroup: [...stepsInStepGroup, step],
+      hasReachedFinalModulator: false,
+    },
+  ).stepsInStepGroup;
+
+  const stepGroupIndentationIncrease = (() => {
+    const traversalSourceIndentationIncrease = stepGroups[0] && isTraversalSource(stepGroups[0].steps[0]) ? 2 : 0;
+    const modulatorIndentationIncrease = isModulator([...stepsInStepGroup, step][0]) ? 2 : 0;
+    const indentationIncrease = traversalSourceIndentationIncrease + modulatorIndentationIncrease;
+    return indentationIncrease;
+  })();
+
+  const recreatedQueryWithSubsequentModulators = recreateQueryOnelinerFromSyntaxTree(
+    config.localIndentation + stepGroupIndentationIncrease,
+  )({
+    type: TokenType.Traversal,
+    steps: stepsWithSubsequentModulators,
+  });
+
+  const lineIsTooLongWithSubsequentModulators = recreatedQueryWithSubsequentModulators.length > config.maxLineLength;
+  return lineIsTooLongWithSubsequentModulators;
+};
+
+// If the first step in a group is a modulator, then it must also be the last step in the group
+export const shouldStepBeLastStepInStepGroup = (config: GremlintInternalConfig) => (
+  {
+    stepsInStepGroup,
+    stepGroups,
+  }: {
+    stepsInStepGroup: FormattedSyntaxTree[];
+    stepGroups: GremlinStepGroup[];
+  },
+  step: UnformattedSyntaxTree,
+  index: number,
+  steps: UnformattedSyntaxTree[],
+) => {
+  const isFirstStepInStepGroup = !stepsInStepGroup.length;
+
+  const isLastStep = index === steps.length - 1;
+  const nextStepIsModulator = !isLastStep && isModulator(steps[index + 1]);
+
+  const lineIsTooLongWithSubsequentModulators = isLineTooLongWithSubsequentModulators(config)(
+    { stepsInStepGroup, stepGroups },
+    step,
+    index,
+    steps,
+  );
+
+  // If the first step in a group is a modulator, then it must also be the last step in the group
+  const stepShouldBeLastStepInStepGroup =
+    isLastStep ||
+    (isFirstStepInStepGroup && isModulator(step)) ||
+    ((step.type === TokenType.Method || step.type === TokenType.Closure) &&
+      !(nextStepIsModulator && !lineIsTooLongWithSubsequentModulators));
+  return stepShouldBeLastStepInStepGroup;
+};
diff --git a/gremlint/src/formatQuery/formatSyntaxTrees/formatTraversal/index.ts b/gremlint/src/formatQuery/formatSyntaxTrees/formatTraversal/index.ts
new file mode 100644
index 0000000..74417f4
--- /dev/null
+++ b/gremlint/src/formatQuery/formatSyntaxTrees/formatTraversal/index.ts
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+import recreateQueryOnelinerFromSyntaxTree from '../../recreateQueryOnelinerFromSyntaxTree';
+import {
+  FormattedSyntaxTree,
+  FormattedTraversalSyntaxTree,
+  GremlinSyntaxTreeFormatter,
+  GremlintInternalConfig,
+  TokenType,
+  UnformattedTraversalSyntaxTree,
+} from '../../types';
+import { last, pipe, sum } from '../../utils';
+import { withIncreasedHorizontalPosition, withZeroIndentation } from '../utils';
+import { getStepGroups } from './getStepGroups';
+import { isTraversalSource } from './getStepGroups/utils';
+
+// Groups steps into step groups and adds a localIndentation property
+export const formatTraversal = (formatSyntaxTree: GremlinSyntaxTreeFormatter) => (config: GremlintInternalConfig) => (
+  syntaxTree: UnformattedTraversalSyntaxTree,
+): FormattedTraversalSyntaxTree => {
+  const initialHorizontalPositionIndentationIncrease =
+    syntaxTree.steps[0] && isTraversalSource(syntaxTree.steps[0]) ? syntaxTree.initialHorizontalPosition : 0;
+  const recreatedQuery = recreateQueryOnelinerFromSyntaxTree(
+    config.localIndentation + initialHorizontalPositionIndentationIncrease,
+  )(syntaxTree);
+  if (recreatedQuery.length <= config.maxLineLength) {
+    return {
+      type: TokenType.Traversal,
+      steps: syntaxTree.steps,
+      stepGroups: [
+        {
+          steps: syntaxTree.steps.reduce((steps, step, stepIndex) => {
+            const formattedStep =
+              stepIndex === 0
+                ? formatSyntaxTree(config)(step)
+                : // Since the traversal's steps will be on the same line, their horizontal position is increased by the
+                  // steps's width plus the width of the dots between them
+                  formatSyntaxTree(
+                    pipe(
+                      withZeroIndentation,
+                      withIncreasedHorizontalPosition(
+                        syntaxTree.initialHorizontalPosition +
+                          steps.map(({ width }) => width).reduce(sum, 0) +
+                          steps.length,
+                      ),
+                    )(config),
+                  )(step);
+            return [...steps, formattedStep];
+          }, [] as FormattedSyntaxTree[]),
+        },
+      ],
+      initialHorizontalPosition: syntaxTree.initialHorizontalPosition,
+      localIndentation: 0,
+      width: recreatedQuery.trim().length,
+    };
+  }
+  const stepGroups = getStepGroups(formatSyntaxTree, syntaxTree.steps, config);
+  const lastStepGroup = last(stepGroups);
+  const width = lastStepGroup
+    ? lastStepGroup.steps.map(({ width }) => width).reduce(sum, 0) + stepGroups.length - 1
+    : 0;
+  return {
+    type: TokenType.Traversal,
+    steps: syntaxTree.steps,
+    stepGroups,
+    initialHorizontalPosition: syntaxTree.initialHorizontalPosition,
+    localIndentation: 0,
+    width,
+  };
+};
diff --git a/gremlint/src/formatQuery/formatSyntaxTrees/formatWord.ts b/gremlint/src/formatQuery/formatSyntaxTrees/formatWord.ts
new file mode 100644
index 0000000..d8304cc
--- /dev/null
+++ b/gremlint/src/formatQuery/formatSyntaxTrees/formatWord.ts
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+import { FormattedWordSyntaxTree, GremlintInternalConfig, TokenType, UnformattedWordSyntaxTree } from '../types';
+
+export const formatWord = (config: GremlintInternalConfig) => (
+  syntaxTree: UnformattedWordSyntaxTree,
+): FormattedWordSyntaxTree => {
+  return {
+    type: TokenType.Word,
+    word: syntaxTree.word,
+    localIndentation: config.localIndentation,
+    shouldStartWithDot: Boolean(config.shouldStartWithDot),
+    shouldEndWithDot: Boolean(config.shouldEndWithDot),
+    width: syntaxTree.word.length,
+  };
+};
diff --git a/gremlint/src/formatQuery/formatSyntaxTrees/index.ts b/gremlint/src/formatQuery/formatSyntaxTrees/index.ts
new file mode 100644
index 0000000..5018e26
--- /dev/null
+++ b/gremlint/src/formatQuery/formatSyntaxTrees/index.ts
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+import { FormattedSyntaxTree, GremlintInternalConfig, TokenType, UnformattedSyntaxTree } from '../types';
+import { formatClosure } from './formatClosure';
+import { formatMethod } from './formatMethod';
+import { formatNonGremlin } from './formatNonGremlin';
+import { formatString } from './formatString';
+import { formatTraversal } from './formatTraversal';
+import { formatWord } from './formatWord';
+
+const formatSyntaxTree = (config: GremlintInternalConfig) => (
+  syntaxTree: UnformattedSyntaxTree,
+): FormattedSyntaxTree => {
+  switch (syntaxTree.type) {
+    case TokenType.NonGremlinCode:
+      return formatNonGremlin(config)(syntaxTree);
+    case TokenType.Traversal:
+      return formatTraversal(formatSyntaxTree)(config)(syntaxTree);
+    case TokenType.Method:
+      return formatMethod(formatSyntaxTree)(config)(syntaxTree);
+    case TokenType.Closure:
+      return formatClosure(formatSyntaxTree)(config)(syntaxTree);
+    case TokenType.String:
+      return formatString(config)(syntaxTree);
+    case TokenType.Word:
+      return formatWord(config)(syntaxTree);
+  }
+};
+
+export const formatSyntaxTrees = (config: GremlintInternalConfig) => (syntaxTrees: UnformattedSyntaxTree[]) => {
+  return syntaxTrees.map(formatSyntaxTree(config));
+};
diff --git a/gremlint/src/formatQuery/formatSyntaxTrees/utils.ts b/gremlint/src/formatQuery/formatSyntaxTrees/utils.ts
new file mode 100644
index 0000000..6b79988
--- /dev/null
+++ b/gremlint/src/formatQuery/formatSyntaxTrees/utils.ts
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+import { GremlintInternalConfig } from '../types';
+
+export const withIndentation = (localIndentation: number) => (
+  config: GremlintInternalConfig,
+): GremlintInternalConfig => ({
+  ...config,
+  localIndentation,
+});
+
+export const withZeroIndentation = withIndentation(0);
+
+export const withIncreasedIndentation = (indentationIncrease: number) => (
+  config: GremlintInternalConfig,
+): GremlintInternalConfig => ({
+  ...config,
+  localIndentation: config.localIndentation + indentationIncrease,
+});
+
+export const withDotInfo = ({
+  shouldStartWithDot,
+  shouldEndWithDot,
+}: {
+  shouldStartWithDot: boolean;
+  shouldEndWithDot: boolean;
+}) => (config: GremlintInternalConfig): GremlintInternalConfig => ({
+  ...config,
+  shouldStartWithDot,
+  shouldEndWithDot,
+});
+
+export const withZeroDotInfo = (config: GremlintInternalConfig): GremlintInternalConfig => ({
+  ...config,
+  shouldStartWithDot: false,
+  shouldEndWithDot: false,
+});
+
+export const withNoEndDotInfo = (config: GremlintInternalConfig): GremlintInternalConfig => ({
+  ...config,
+  shouldEndWithDot: false,
+});
+
+export const withHorizontalPosition = (horizontalPosition: number) => (
+  config: GremlintInternalConfig,
+): GremlintInternalConfig => ({
+  ...config,
+  horizontalPosition,
+});
+
+export const withIncreasedHorizontalPosition = (horizontalPositionIncrease: number) => (
+  config: GremlintInternalConfig,
+): GremlintInternalConfig => ({
+  ...config,
+  horizontalPosition: config.horizontalPosition + horizontalPositionIncrease,
+});
diff --git a/gremlint/src/formatQuery/index.ts b/gremlint/src/formatQuery/index.ts
new file mode 100644
index 0000000..4f27e3e
--- /dev/null
+++ b/gremlint/src/formatQuery/index.ts
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+import { formatSyntaxTrees } from './formatSyntaxTrees';
+import { parseToSyntaxTrees } from './parseToSyntaxTrees';
+import { recreateQueryStringFromFormattedSyntaxTrees } from './recreateQueryStringFromFormattedSyntaxTrees';
+import { GremlintInternalConfig, GremlintUserConfig } from './types';
+import { pipe } from './utils';
+
+const withDefaults = (config: Partial<GremlintUserConfig>): GremlintUserConfig => ({
+  indentation: 0,
+  maxLineLength: 80,
+  shouldPlaceDotsAfterLineBreaks: false,
+  ...config,
+});
+
+const getInternalGremlintConfig = ({
+  indentation,
+  maxLineLength,
+  shouldPlaceDotsAfterLineBreaks,
+}: GremlintUserConfig): GremlintInternalConfig => ({
+  globalIndentation: indentation,
+  localIndentation: 0,
+  maxLineLength: maxLineLength - indentation,
+  shouldPlaceDotsAfterLineBreaks,
+  shouldStartWithDot: false,
+  shouldEndWithDot: false,
+  horizontalPosition: 0,
+});
+
+export const formatQuery = (query: string, config?: Partial<GremlintUserConfig>): string => {
+  const internalConfig = getInternalGremlintConfig(withDefaults(config ?? {}));
+  return pipe(
+    parseToSyntaxTrees,
+    formatSyntaxTrees(internalConfig),
+    recreateQueryStringFromFormattedSyntaxTrees(internalConfig),
+  )(query);
+};
diff --git a/gremlint/src/formatQuery/parseToSyntaxTrees/__tests__/extractGremlinQueries.test.ts b/gremlint/src/formatQuery/parseToSyntaxTrees/__tests__/extractGremlinQueries.test.ts
new file mode 100644
index 0000000..d66fb2e
--- /dev/null
+++ b/gremlint/src/formatQuery/parseToSyntaxTrees/__tests__/extractGremlinQueries.test.ts
@@ -0,0 +1,564 @@
+/*
+ * 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.
+ */
+
+import { extractGremlinQueries } from '../extractGremlinQueries';
+
+test('Extract the parts of the code that can be parsed as Gremlin', () => {
+  expect(
+    extractGremlinQueries(
+      `graph = TinkerFactory.createModern()
+g = graph.traversal()
+g.V().has('name','marko').out('knows').values('name')`,
+    ),
+  ).toStrictEqual([`g.V().has('name','marko').out('knows').values('name')`]);
+
+  expect(
+    extractGremlinQueries(
+      `g.V().has('name','marko').next()
+g.V(marko).out('knows')
+g.V(marko).out('knows').values('name')`,
+    ),
+  ).toStrictEqual([
+    `g.V().has('name','marko').next()`,
+    `g.V(marko).out('knows')`,
+    `g.V(marko).out('knows').values('name')`,
+  ]);
+
+  expect(
+    extractGremlinQueries(
+      `g = graph.traversal();
+List<Vertex> vertices = g.V().toList()`,
+    ),
+  ).toStrictEqual([`g.V().toList()`]);
+
+  expect(
+    extractGremlinQueries(
+      `v1 = g.addV('person').property('name','marko').next()
+v2 = g.addV('person').property('name','stephen').next()
+g.V(v1).addE('knows').to(v2).property('weight',0.75).iterate()`,
+    ),
+  ).toStrictEqual([
+    `g.addV('person').property('name','marko').next()`,
+    `g.addV('person').property('name','stephen').next()`,
+    `g.V(v1).addE('knows').to(v2).property('weight',0.75).iterate()`,
+  ]);
+
+  expect(
+    extractGremlinQueries(
+      `marko = g.V().has('person','name','marko').next()
+peopleMarkoKnows = g.V().has('person','name','marko').out('knows').toList()`,
+    ),
+  ).toStrictEqual([
+    `g.V().has('person','name','marko').next()`,
+    `g.V().has('person','name','marko').out('knows').toList()`,
+  ]);
+
+  expect(
+    extractGremlinQueries(
+      `graph = TinkerGraph.open()
+g = graph.traversal()
+v = g.addV().property('name','marko').property('name','marko a. rodriguez').next()
+g.V(v).properties('name').count()
+v.property(list, 'name', 'm. a. rodriguez')
+g.V(v).properties('name').count()
+g.V(v).properties()
+g.V(v).properties('name')
+g.V(v).properties('name').hasValue('marko')
+g.V(v).properties('name').hasValue('marko').property('acl','private')
+g.V(v).properties('name').hasValue('marko a. rodriguez')
+g.V(v).properties('name').hasValue('marko a. rodriguez').property('acl','public')
+g.V(v).properties('name').has('acl','public').value()
+g.V(v).properties('name').has('acl','public').drop()
+g.V(v).properties('name').has('acl','public').value()
+g.V(v).properties('name').has('acl','private').value()
+g.V(v).properties()
+g.V(v).properties().properties()
+g.V(v).properties().property('date',2014)
+g.V(v).properties().property('creator','stephen')
+g.V(v).properties().properties()
+g.V(v).properties('name').valueMap()
+g.V(v).property('name','okram')
+g.V(v).properties('name')
+g.V(v).values('name')`,
+    ),
+  ).toStrictEqual([
+    `g.addV().property('name','marko').property('name','marko a. rodriguez').next()`,
+    `g.V(v).properties('name').count()`,
+    `g.V(v).properties('name').count()`,
+    `g.V(v).properties()`,
+    `g.V(v).properties('name')`,
+    `g.V(v).properties('name').hasValue('marko')`,
+    `g.V(v).properties('name').hasValue('marko').property('acl','private')`,
+    `g.V(v).properties('name').hasValue('marko a. rodriguez')`,
+    `g.V(v).properties('name').hasValue('marko a. rodriguez').property('acl','public')`,
+    `g.V(v).properties('name').has('acl','public').value()`,
+    `g.V(v).properties('name').has('acl','public').drop()`,
+    `g.V(v).properties('name').has('acl','public').value()`,
+    `g.V(v).properties('name').has('acl','private').value()`,
+    `g.V(v).properties()`,
+    `g.V(v).properties().properties()`,
+    `g.V(v).properties().property('date',2014)`,
+    `g.V(v).properties().property('creator','stephen')`,
+    `g.V(v).properties().properties()`,
+    `g.V(v).properties('name').valueMap()`,
+    `g.V(v).property('name','okram')`,
+    `g.V(v).properties('name')`,
+    `g.V(v).values('name')`,
+  ]);
+
+  expect(
+    extractGremlinQueries(
+      `g.V().as('a').
+      properties('location').as('b').
+      hasNot('endTime').as('c').
+      select('a','b','c').by('name').by(value).by('startTime') // determine the current location of each person
+g.V().has('name','gremlin').inE('uses').
+      order().by('skill',asc).as('a').
+      outV().as('b').
+      select('a','b').by('skill').by('name') // rank the users of gremlin by their skill level`,
+    ),
+  ).toStrictEqual([
+    `g.V().as('a').
+      properties('location').as('b').
+      hasNot('endTime').as('c').
+      select('a','b','c').by('name').by(value).by('startTime')`,
+    `g.V().has('name','gremlin').inE('uses').
+      order().by('skill',asc).as('a').
+      outV().as('b').
+      select('a','b').by('skill').by('name')`,
+  ]);
+
+  expect(
+    extractGremlinQueries(
+      `g.V(1).out().values('name')
+g.V(1).out().map {it.get().value('name')}
+g.V(1).out().map(values('name'))`,
+    ),
+  ).toStrictEqual([
+    `g.V(1).out().values('name')`,
+    `g.V(1).out().map {it.get().value('name')}`,
+    `g.V(1).out().map(values('name'))`,
+  ]);
+
+  expect(
+    extractGremlinQueries(
+      `g.V().filter {it.get().label() == 'person'}
+g.V().filter(label().is('person'))
+g.V().hasLabel('person')`,
+    ),
+  ).toStrictEqual([
+    `g.V().filter {it.get().label() == 'person'}`,
+    `g.V().filter(label().is('person'))`,
+    `g.V().hasLabel('person')`,
+  ]);
+
+  expect(
+    extractGremlinQueries(
+      `g.V().hasLabel('person').sideEffect(System.out.&println)
+g.V().sideEffect(outE().count().store("o")).
+      sideEffect(inE().count().store("i")).cap("o","i")`,
+    ),
+  ).toStrictEqual([
+    `g.V().hasLabel('person').sideEffect(System.out.&println)`,
+    `g.V().sideEffect(outE().count().store("o")).
+      sideEffect(inE().count().store("i")).cap("o","i")`,
+  ]);
+
+  expect(
+    extractGremlinQueries(
+      `g.V().branch {it.get().value('name')}.
+      option('marko', values('age')).
+      option(none, values('name'))
+g.V().branch(values('name')).
+      option('marko', values('age')).
+      option(none, values('name'))
+g.V().choose(has('name','marko'),
+             values('age'),
+             values('name'))`,
+    ),
+  ).toStrictEqual([
+    `g.V().branch {it.get().value('name')}.
+      option('marko', values('age')).
+      option(none, values('name'))`,
+    `g.V().branch(values('name')).
+      option('marko', values('age')).
+      option(none, values('name'))`,
+    `g.V().choose(has('name','marko'),
+             values('age'),
+             values('name'))`,
+  ]);
+
+  expect(
+    extractGremlinQueries(
+      `g.V().out('created').hasNext()
+g.V().out('created').next()
+g.V().out('created').next(2)
+g.V().out('nothing').tryNext()
+g.V().out('created').toList()
+g.V().out('created').toSet()
+g.V().out('created').toBulkSet()
+results = ['blah',3]
+g.V().out('created').fill(results)
+g.addV('person').iterate()`,
+    ),
+  ).toStrictEqual([
+    `g.V().out('created').hasNext()`,
+    `g.V().out('created').next()`,
+    `g.V().out('created').next(2)`,
+    `g.V().out('nothing').tryNext()`,
+    `g.V().out('created').toList()`,
+    `g.V().out('created').toSet()`,
+    `g.V().out('created').toBulkSet()`,
+    `g.V().out('created').fill(results)`,
+    `g.addV('person').iterate()`,
+  ]);
+
+  expect(
+    extractGremlinQueries(
+      `g.V(1).as('a').out('created').in('created').where(neq('a')).
+  addE('co-developer').from('a').property('year',2009)
+g.V(3,4,5).aggregate('x').has('name','josh').as('a').
+  select('x').unfold().hasLabel('software').addE('createdBy').to('a')
+g.V().as('a').out('created').addE('createdBy').to('a').property('acl','public')
+g.V(1).as('a').out('knows').
+  addE('livesNear').from('a').property('year',2009).
+  inV().inE('livesNear').values('year')
+g.V().match(
+        __.as('a').out('knows').as('b'),
+        __.as('a').out('created').as('c'),
+        __.as('b').out('created').as('c')).
+      addE('friendlyCollaborator').from('a').to('b').
+        property(id,23).property('project',select('c').values('name'))
+g.E(23).valueMap()
+marko = g.V().has('name','marko').next()
+peter = g.V().has('name','peter').next()
+g.V(marko).addE('knows').to(peter)
+g.addE('knows').from(marko).to(peter)`,
+    ),
+  ).toStrictEqual([
+    `g.V(1).as('a').out('created').in('created').where(neq('a')).
+  addE('co-developer').from('a').property('year',2009)`,
+    `g.V(3,4,5).aggregate('x').has('name','josh').as('a').
+  select('x').unfold().hasLabel('software').addE('createdBy').to('a')`,
+    `g.V().as('a').out('created').addE('createdBy').to('a').property('acl','public')`,
+    `g.V(1).as('a').out('knows').
+  addE('livesNear').from('a').property('year',2009).
+  inV().inE('livesNear').values('year')`,
+    `g.V().match(
+        __.as('a').out('knows').as('b'),
+        __.as('a').out('created').as('c'),
+        __.as('b').out('created').as('c')).
+      addE('friendlyCollaborator').from('a').to('b').
+        property(id,23).property('project',select('c').values('name'))`,
+    `g.E(23).valueMap()`,
+    `g.V().has('name','marko').next()`,
+    `g.V().has('name','peter').next()`,
+    `g.V(marko).addE('knows').to(peter)`,
+    `g.addE('knows').from(marko).to(peter)`,
+  ]);
+
+  expect(
+    extractGremlinQueries(
+      `g.addV('person').property('name','stephen')
+g.V().values('name')
+g.V().outE('knows').addV().property('name','nothing')
+g.V().has('name','nothing')
+g.V().has('name','nothing').bothE()`,
+    ),
+  ).toStrictEqual([
+    `g.addV('person').property('name','stephen')`,
+    `g.V().values('name')`,
+    `g.V().outE('knows').addV().property('name','nothing')`,
+    `g.V().has('name','nothing')`,
+    `g.V().has('name','nothing').bothE()`,
+  ]);
+
+  expect(
+    extractGremlinQueries(
+      `g.V(1).property('country','usa')
+g.V(1).property('city','santa fe').property('state','new mexico').valueMap()
+g.V(1).property(list,'age',35)
+g.V(1).valueMap()
+g.V(1).property('friendWeight',outE('knows').values('weight').sum(),'acl','private')
+g.V(1).properties('friendWeight').valueMap()`,
+    ),
+  ).toStrictEqual([
+    `g.V(1).property('country','usa')`,
+    `g.V(1).property('city','santa fe').property('state','new mexico').valueMap()`,
+    `g.V(1).property(list,'age',35)`,
+    `g.V(1).valueMap()`,
+    `g.V(1).property('friendWeight',outE('knows').values('weight').sum(),'acl','private')`,
+    `g.V(1).properties('friendWeight').valueMap()`,
+  ]);
+
+  expect(
+    extractGremlinQueries(
+      `g.V(1).out('created')
+g.V(1).out('created').aggregate('x')
+g.V(1).out('created').aggregate(global, 'x')
+g.V(1).out('created').aggregate('x').in('created')
+g.V(1).out('created').aggregate('x').in('created').out('created')
+g.V(1).out('created').aggregate('x').in('created').out('created').
+       where(without('x')).values('name')`,
+    ),
+  ).toStrictEqual([
+    `g.V(1).out('created')`,
+    `g.V(1).out('created').aggregate('x')`,
+    `g.V(1).out('created').aggregate(global, 'x')`,
+    `g.V(1).out('created').aggregate('x').in('created')`,
+    `g.V(1).out('created').aggregate('x').in('created').out('created')`,
+    `g.V(1).out('created').aggregate('x').in('created').out('created').
+       where(without('x')).values('name')`,
+  ]);
+
+  expect(
+    extractGremlinQueries(
+      `g.V().out('knows').aggregate('x').cap('x')
+g.V().out('knows').aggregate('x').by('name').cap('x')`,
+    ),
+  ).toStrictEqual([
+    `g.V().out('knows').aggregate('x').cap('x')`,
+    `g.V().out('knows').aggregate('x').by('name').cap('x')`,
+  ]);
+
+  expect(
+    extractGremlinQueries(
+      `g.V().aggregate(global, 'x').limit(1).cap('x')
+g.V().aggregate(local, 'x').limit(1).cap('x')
+g.withoutStrategies(EarlyLimitStrategy).V().aggregate(local,'x').limit(1).cap('x')`,
+    ),
+  ).toStrictEqual([
+    `g.V().aggregate(global, 'x').limit(1).cap('x')`,
+    `g.V().aggregate(local, 'x').limit(1).cap('x')`,
+    `g.withoutStrategies(EarlyLimitStrategy).V().aggregate(local,'x').limit(1).cap('x')`,
+  ]);
+
+  expect(
+    extractGremlinQueries(
+      `g.V().as('a').out('created').as('b').select('a','b')
+g.V().as('a').out('created').as('b').select('a','b').by('name')`,
+    ),
+  ).toStrictEqual([
+    `g.V().as('a').out('created').as('b').select('a','b')`,
+    `g.V().as('a').out('created').as('b').select('a','b').by('name')`,
+  ]);
+
+  expect(
+    extractGremlinQueries(
+      `g.V().sideEffect{println "first: \${it}"}.sideEffect{println "second: \${it}"}.iterate()
+g.V().sideEffect{println "first: \${it}"}.barrier().sideEffect{println "second: \${it}"}.iterate()`,
+    ),
+  ).toStrictEqual([
+    `g.V().sideEffect{println "first: \${it}"}.sideEffect{println "second: \${it}"}.iterate()`,
+    `g.V().sideEffect{println "first: \${it}"}.barrier().sideEffect{println "second: \${it}"}.iterate()`,
+  ]);
+
+  expect(
+    extractGremlinQueries(
+      `graph = TinkerGraph.open()
+g = graph.traversal()
+g.io('data/grateful-dead.xml').read().iterate()
+g = graph.traversal().withoutStrategies(LazyBarrierStrategy)
+clockWithResult(1){g.V().both().both().both().count().next()}
+clockWithResult(1){g.V().repeat(both()).times(3).count().next()}
+clockWithResult(1){g.V().both().barrier().both().barrier().both().barrier().count().next()}`,
+    ),
+  ).toStrictEqual([`g.io('data/grateful-dead.xml').read().iterate()`]);
+
+  expect(
+    extractGremlinQueries(
+      `graph = TinkerGraph.open()
+g = graph.traversal()
+g.io('data/grateful-dead.xml').read().iterate()
+clockWithResult(1){g.V().both().both().both().count().next()}
+g.V().both().both().both().count().iterate().toString()`,
+    ),
+  ).toStrictEqual([
+    `g.io('data/grateful-dead.xml').read().iterate()`,
+    `g.V().both().both().both().count().iterate().toString()`,
+  ]);
+
+  expect(
+    extractGremlinQueries(
+      `g.V().group().by(bothE().count())
+g.V().group().by(bothE().count()).by('name')
+g.V().group().by(bothE().count()).by(count())`,
+    ),
+  ).toStrictEqual([
+    `g.V().group().by(bothE().count())`,
+    `g.V().group().by(bothE().count()).by('name')`,
+    `g.V().group().by(bothE().count()).by(count())`,
+  ]);
+
+  expect(
+    extractGremlinQueries(
+      `g.V().groupCount('a').by(label).cap('a')
+g.V().groupCount('a').by(label).groupCount('b').by(outE().count()).cap('a','b')`,
+    ),
+  ).toStrictEqual([
+    `g.V().groupCount('a').by(label).cap('a')`,
+    `g.V().groupCount('a').by(label).groupCount('b').by(outE().count()).cap('a','b')`,
+  ]);
+
+  expect(
+    extractGremlinQueries(
+      `g.V().hasLabel('person').
+      choose(values('age').is(lte(30)),
+        __.in(),
+        __.out()).values('name')
+g.V().hasLabel('person').
+      choose(values('age')).
+        option(27, __.in()).
+        option(32, __.out()).values('name')`,
+    ),
+  ).toStrictEqual([
+    `g.V().hasLabel('person').
+      choose(values('age').is(lte(30)),
+        __.in(),
+        __.out()).values('name')`,
+    `g.V().hasLabel('person').
+      choose(values('age')).
+        option(27, __.in()).
+        option(32, __.out()).values('name')`,
+  ]);
+
+  expect(
+    extractGremlinQueries(
+      `g.V().choose(hasLabel('person'), out('created')).values('name')
+g.V().choose(hasLabel('person'), out('created'), identity()).values('name')`,
+    ),
+  ).toStrictEqual([
+    `g.V().choose(hasLabel('person'), out('created')).values('name')`,
+    `g.V().choose(hasLabel('person'), out('created'), identity()).values('name')`,
+  ]);
+
+  expect(
+    extractGremlinQueries(
+      `g.V(1).coalesce(outE('knows'), outE('created')).inV().path().by('name').by(label)
+g.V(1).coalesce(outE('created'), outE('knows')).inV().path().by('name').by(label)
+g.V(1).property('nickname', 'okram')
+g.V().hasLabel('person').coalesce(values('nickname'), values('name'))`,
+    ),
+  ).toStrictEqual([
+    `g.V(1).coalesce(outE('knows'), outE('created')).inV().path().by('name').by(label)`,
+    `g.V(1).coalesce(outE('created'), outE('knows')).inV().path().by('name').by(label)`,
+    `g.V(1).property('nickname', 'okram')`,
+    `g.V().hasLabel('person').coalesce(values('nickname'), values('name'))`,
+  ]);
+
+  expect(
+    extractGremlinQueries(
+      `g.V().coin(0.5)
+g.V().coin(0.0)
+g.V().coin(1.0)`,
+    ),
+  ).toStrictEqual([`g.V().coin(0.5)`, `g.V().coin(0.0)`, `g.V().coin(1.0)`]);
+
+  expect(
+    extractGremlinQueries(
+      `g.V().
+  connectedComponent().
+    with(ConnectedComponent.propertyName, 'component').
+  project('name','component').
+    by('name').
+    by('component')
+g.V().hasLabel('person').
+  connectedComponent().
+    with(ConnectedComponent.propertyName, 'component').
+    with(ConnectedComponent.edges, outE('knows')).
+  project('name','component').
+    by('name').
+    by('component')`,
+    ),
+  ).toStrictEqual([
+    `g.V().
+  connectedComponent().
+    with(ConnectedComponent.propertyName, 'component').
+  project('name','component').
+    by('name').
+    by('component')`,
+    `g.V().hasLabel('person').
+  connectedComponent().
+    with(ConnectedComponent.propertyName, 'component').
+    with(ConnectedComponent.edges, outE('knows')).
+  project('name','component').
+    by('name').
+    by('component')`,
+  ]);
+
+  expect(
+    extractGremlinQueries(
+      `g.V().choose(hasLabel('person'),
+    values('name'),
+    constant('inhuman'))
+g.V().coalesce(
+    hasLabel('person').values('name'),
+    constant('inhuman'))`,
+    ),
+  ).toStrictEqual([
+    `g.V().choose(hasLabel('person'),
+    values('name'),
+    constant('inhuman'))`,
+    `g.V().coalesce(
+    hasLabel('person').values('name'),
+    constant('inhuman'))`,
+  ]);
+
+  expect(
+    extractGremlinQueries(
+      `g.V().count()
+g.V().hasLabel('person').count()
+g.V().hasLabel('person').outE('created').count().path()
+g.V().hasLabel('person').outE('created').count().map {it.get() * 10}.path()`,
+    ),
+  ).toStrictEqual([
+    `g.V().count()`,
+    `g.V().hasLabel('person').count()`,
+    `g.V().hasLabel('person').outE('created').count().path()`,
+    `g.V().hasLabel('person').outE('created').count().map {it.get() * 10}.path()`,
+  ]);
+
+  expect(
+    extractGremlinQueries(
+      `g.V(1).both().both()
+g.V(1).both().both().cyclicPath()
+g.V(1).both().both().cyclicPath().path()
+g.V(1).as('a').out('created').as('b').
+  in('created').as('c').
+  cyclicPath().
+  path()
+g.V(1).as('a').out('created').as('b').
+  in('created').as('c').
+  cyclicPath().from('a').to('b').
+  path()`,
+    ),
+  ).toStrictEqual([
+    `g.V(1).both().both()`,
+    `g.V(1).both().both().cyclicPath()`,
+    `g.V(1).both().both().cyclicPath().path()`,
+    `g.V(1).as('a').out('created').as('b').
+  in('created').as('c').
+  cyclicPath().
+  path()`,
+    `g.V(1).as('a').out('created').as('b').
+  in('created').as('c').
+  cyclicPath().from('a').to('b').
+  path()`,
+  ]);
+});
diff --git a/gremlint/src/formatQuery/parseToSyntaxTrees/extractGremlinQueries.ts b/gremlint/src/formatQuery/parseToSyntaxTrees/extractGremlinQueries.ts
new file mode 100644
index 0000000..ab00746
--- /dev/null
+++ b/gremlint/src/formatQuery/parseToSyntaxTrees/extractGremlinQueries.ts
@@ -0,0 +1,173 @@
+/*
+ * 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.
+ */
+
+const LEFT_WHITE_PARENTHESIS = '⦅';
+const RIGHT_WHITE_PARENTHESIS = '⦆';
+const LEFT_WHITE_SQUARE_BRACKET = '⟦';
+const RIGHT_WHITE_SQUARE_BRACKET = '⟧';
+const LEFT_WHITE_CURLY_BRACKET = '⦃';
+const RIGHT_WHITE_CURLY_BRACKET = '⦄';
+const WHITE_DOT = '。';
+
+const encodeAllNestedBracketsAndDots = (code: string): string => {
+  const { word } = code.split('').reduce(
+    (state, char) => {
+      if (char === '.') {
+        return {
+          ...state,
+          word:
+            !state.isInsideSingleQuoteString &&
+            !state.parenthesesCount &&
+            !state.squareBracketsCount &&
+            !state.curlyBracketsCount
+              ? state.word + '.'
+              : state.word + WHITE_DOT,
+        };
+      }
+      if (char === '(') {
+        return {
+          ...state,
+          parenthesesCount: state.parenthesesCount + (state.isInsideSingleQuoteString ? 0 : 1),
+          word:
+            !state.isInsideSingleQuoteString &&
+            !state.parenthesesCount &&
+            !state.squareBracketsCount &&
+            !state.curlyBracketsCount
+              ? state.word + '('
+              : state.word + LEFT_WHITE_PARENTHESIS,
+        };
+      }
+      if (char === '[') {
+        return {
+          ...state,
+          squareBracketsCount: state.squareBracketsCount + (state.isInsideSingleQuoteString ? 0 : 1),
+          word:
+            !state.isInsideSingleQuoteString &&
+            !state.parenthesesCount &&
+            !state.squareBracketsCount &&
+            !state.curlyBracketsCount
+              ? state.word + '['
+              : state.word + LEFT_WHITE_SQUARE_BRACKET,
+        };
+      }
+      if (char === '{') {
+        return {
+          ...state,
+          curlyBracketsCount: state.curlyBracketsCount + (state.isInsideSingleQuoteString ? 0 : 1),
+          word:
+            !state.isInsideSingleQuoteString &&
+            !state.parenthesesCount &&
+            !state.squareBracketsCount &&
+            !state.curlyBracketsCount
+              ? state.word + '{'
+              : state.word + LEFT_WHITE_CURLY_BRACKET,
+        };
+      }
+      if (char === ')') {
+        return {
+          ...state,
+          parenthesesCount: state.parenthesesCount - (state.isInsideSingleQuoteString ? 0 : 1),
+          word:
+            !state.isInsideSingleQuoteString &&
+            state.parenthesesCount === 1 &&
+            !state.squareBracketsCount &&
+            !state.curlyBracketsCount
+              ? state.word + ')'
+              : state.word + RIGHT_WHITE_PARENTHESIS,
+        };
+      }
+      if (char === ']') {
+        return {
+          ...state,
+          squareBracketsCount: state.squareBracketsCount - (state.isInsideSingleQuoteString ? 0 : 1),
+          word:
+            !state.isInsideSingleQuoteString &&
+            !state.parenthesesCount &&
+            state.squareBracketsCount === 1 &&
+            !state.curlyBracketsCount
+              ? state.word + ']'
+              : state.word + RIGHT_WHITE_SQUARE_BRACKET,
+        };
+      }
+      if (char === '}') {
+        return {
+          ...state,
+          curlyBracketsCount: state.curlyBracketsCount - (state.isInsideSingleQuoteString ? 0 : 1),
+          word:
+            !state.isInsideSingleQuoteString &&
+            !state.parenthesesCount &&
+            !state.squareBracketsCount &&
+            state.curlyBracketsCount === 1
+              ? state.word + '}'
+              : state.word + RIGHT_WHITE_CURLY_BRACKET,
+        };
+      }
+      if (char === "'") {
+        return {
+          ...state,
+          isInsideSingleQuoteString: !state.isInsideSingleQuoteString,
+          word: state.word + "'",
+        };
+      }
+      return {
+        ...state,
+        word: state.word + char,
+      };
+    },
+    { word: '', parenthesesCount: 0, squareBracketsCount: 0, curlyBracketsCount: 0, isInsideSingleQuoteString: false },
+  );
+  return word;
+};
+
+const decodeEncodedBracketsAndDots = (code: string) => {
+  return code
+    .split(WHITE_DOT)
+    .join('.')
+    .split(LEFT_WHITE_PARENTHESIS)
+    .join('(')
+    .split(RIGHT_WHITE_PARENTHESIS)
+    .join(')')
+    .split(LEFT_WHITE_SQUARE_BRACKET)
+    .join('[')
+    .split(RIGHT_WHITE_SQUARE_BRACKET)
+    .join(']')
+    .split(LEFT_WHITE_CURLY_BRACKET)
+    .join('{')
+    .split(RIGHT_WHITE_CURLY_BRACKET)
+    .join('}');
+};
+
+const SPACE = `\\s`;
+const HORIZONTAL_SPACE = `[^\\S\\r\\n]`;
+const DOT = `\\.`;
+const METHOD_STEP = `\\w+${HORIZONTAL_SPACE}*\\([^\\)]*\\)`;
+const CLOSURE_STEP = `\\w+${HORIZONTAL_SPACE}*\\{[^\\}]*\\}`;
+const WORD_STEP = `\\w+`;
+const GREMLIN_STEP = `(${METHOD_STEP}|${CLOSURE_STEP}|${WORD_STEP})`;
+const STEP_CONNECTOR = `(${SPACE}*${DOT}${SPACE}*)`;
+const GREMLIN_QUERY = `g(${STEP_CONNECTOR}${GREMLIN_STEP})+`;
+
+const gremlinQueryRegExp = new RegExp(GREMLIN_QUERY, 'g');
+
+export const extractGremlinQueries = (code: string) => {
+  const encodedCode = encodeAllNestedBracketsAndDots(code);
+  const gremlinQueries = encodedCode.match(gremlinQueryRegExp);
+  if (!gremlinQueries) return [];
+  return gremlinQueries.map(decodeEncodedBracketsAndDots);
+};
diff --git a/gremlint/src/formatQuery/parseToSyntaxTrees/index.ts b/gremlint/src/formatQuery/parseToSyntaxTrees/index.ts
new file mode 100644
index 0000000..ad5f8a2
--- /dev/null
+++ b/gremlint/src/formatQuery/parseToSyntaxTrees/index.ts
@@ -0,0 +1,391 @@
+/*
+ * 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.
+ */
+
+import {
+  UnformattedClosureCodeBlock,
+  TokenType,
+  UnformattedSyntaxTree,
+  UnformattedNonGremlinSyntaxTree,
+} from '../types';
+import { last, neq, pipe } from '../utils';
+import { extractGremlinQueries } from './extractGremlinQueries';
+
+const tokenizeOnTopLevelPunctuation = (query: string): string[] => {
+  let word = '';
+  let parenthesesCount = 0;
+  let squareBracketCount = 0;
+  let curlyBracketCount = 0;
+  let isInsideSingleQuoteString = false;
+  query.split('').forEach((char) => {
+    if (char === '(' && !isInsideSingleQuoteString) {
+      parenthesesCount++;
+      word += '(';
+      return;
+    }
+    if (char === '[' && !isInsideSingleQuoteString) {
+      squareBracketCount++;
+      word += '[';
+      return;
+    }
+    if (char === '{' && !isInsideSingleQuoteString) {
+      curlyBracketCount++;
+      word += '{';
+      return;
+    }
+    if (char === ')' && !isInsideSingleQuoteString) {
+      parenthesesCount--;
+      word += ')';
+      return;
+    }
+    if (char === ']' && !isInsideSingleQuoteString) {
+      squareBracketCount--;
+      word += ']';
+      return;
+    }
+    if (char === '}' && !isInsideSingleQuoteString) {
+      curlyBracketCount--;
+      word += '}';
+      return;
+    }
+    if (char === "'") {
+      isInsideSingleQuoteString = !isInsideSingleQuoteString;
+      word += "'";
+      return;
+    }
+    if (char === '.') {
+      word +=
+        isInsideSingleQuoteString || parenthesesCount || squareBracketCount || curlyBracketCount
+          ? '.'
+          : String.fromCharCode(28);
+      return;
+    }
+    word += char;
+  });
+  return word
+    .split(String.fromCharCode(28))
+    .filter((token) => token !== '')
+    .map((token) => token.trim());
+};
+
+const tokenizeOnTopLevelComma = (query: string): string[] => {
+  let word = '';
+  let parenthesesCount = 0;
+  let squareBracketsCount = 0;
+  let curlyBracketsCount = 0;
+  let isInsideSingleQuoteString = false;
+  query.split('').forEach((char) => {
+    if (char === '(' && !isInsideSingleQuoteString) {
+      parenthesesCount++;
+      word += '(';
+      return;
+    }
+    if (char === '[' && !isInsideSingleQuoteString) {
+      squareBracketsCount++;
+      word += '[';
+      return;
+    }
+    if (char === '{' && !isInsideSingleQuoteString) {
+      curlyBracketsCount++;
+      word += '{';
+      return;
+    }
+    if (char === ')' && !isInsideSingleQuoteString) {
+      parenthesesCount--;
+      word += ')';
+      return;
+    }
+    if (char === ']' && !isInsideSingleQuoteString) {
+      squareBracketsCount--;
+      word += ']';
+      return;
+    }
+    if (char === '}' && !isInsideSingleQuoteString) {
+      curlyBracketsCount--;
+      word += '}';
+      return;
+    }
+    if (char === "'") {
+      isInsideSingleQuoteString = !isInsideSingleQuoteString;
+      word += "'";
+      return;
+    }
+    if (char === ',') {
+      word +=
+        isInsideSingleQuoteString || parenthesesCount || squareBracketsCount || curlyBracketsCount
+          ? ','
+          : String.fromCharCode(28);
+      return;
+    }
+    word += char;
+  });
+  return word
+    .split(String.fromCharCode(28))
+    .filter((token) => token !== '')
+    .map((token) => token.trim());
+};
+
+const tokenizeOnTopLevelParentheses = (query: string): string[] => {
+  let word = '';
+  let parenthesesCount = 0;
+  let squareBracketsCount = 0;
+  let curlyBracketsCount = 0;
+  let isInsideSingleQuoteString = false;
+  query.split('').forEach((char) => {
+    if (char === '(' && !isInsideSingleQuoteString) {
+      if (parenthesesCount === 0) {
+        word += String.fromCharCode(28);
+      }
+      parenthesesCount++;
+      word += '(';
+      return;
+    }
+    if (char === '[' && !isInsideSingleQuoteString) {
+      squareBracketsCount++;
+      word += '[';
+      return;
+    }
+    if (char === '{' && !isInsideSingleQuoteString) {
+      curlyBracketsCount++;
+      word += '{';
+      return;
+    }
+    if (char === ')' && !isInsideSingleQuoteString) {
+      parenthesesCount--;
+      word += ')';
+      return;
+    }
+    if (char === ']' && !isInsideSingleQuoteString) {
+      squareBracketsCount--;
+      word += ']';
+      return;
+    }
+    if (char === '}' && !isInsideSingleQuoteString) {
+      curlyBracketsCount--;
+      word += '}';
+      return;
+    }
+    if (char === "'") {
+      isInsideSingleQuoteString = !isInsideSingleQuoteString;
+      word += "'";
+      return;
+    }
+    word += char;
+  });
+  return word
+    .split(String.fromCharCode(28))
+    .filter((token) => token !== '')
+    .map((token) => token.trim());
+};
+
+const tokenizeOnTopLevelCurlyBrackets = (query: string): string[] => {
+  let word = '';
+  let parenthesesCount = 0;
+  let squareBracketsCount = 0;
+  let curlyBracketsCount = 0;
+  let isInsideSingleQuoteString = false;
+  query.split('').forEach((char) => {
+    if (char === '(' && !isInsideSingleQuoteString) {
+      parenthesesCount++;
+      word += '(';
+      return;
+    }
+    if (char === '[' && !isInsideSingleQuoteString) {
+      squareBracketsCount++;
+      word += '[';
+      return;
+    }
+    if (char === '{' && !isInsideSingleQuoteString) {
+      if (curlyBracketsCount === 0) {
+        word += String.fromCharCode(28);
+      }
+      curlyBracketsCount++;
+      word += '{';
+      return;
+    }
+    if (char === ')' && !isInsideSingleQuoteString) {
+      parenthesesCount--;
+      word += ')';
+      return;
+    }
+    if (char === ']' && !isInsideSingleQuoteString) {
+      squareBracketsCount--;
+      word += ']';
+      return;
+    }
+    if (char === '}' && !isInsideSingleQuoteString) {
+      curlyBracketsCount--;
+      word += '}';
+      return;
+    }
+    if (char === "'") {
+      isInsideSingleQuoteString = !isInsideSingleQuoteString;
+      word += "'";
+      return;
+    }
+    word += char;
+  });
+  return word
+    .split(String.fromCharCode(28))
+    .filter((token) => token !== '')
+    .map((token) => token.trim());
+};
+
+const isWrappedInParentheses = (token: string): boolean => {
+  if (token.length < 2) return false;
+  if (token.charAt(0) !== '(') return false;
+  if (token.slice(-1) !== ')') return false;
+  return true;
+};
+
+const isWrappedInCurlyBrackets = (token: string): boolean => {
+  if (token.length < 2) return false;
+  if (token.charAt(0) !== '{') return false;
+  if (token.slice(-1) !== '}') return false;
+  return true;
+};
+
+const isString = (token: string): boolean => {
+  if (token.length < 2) return false;
+  if (token.charAt(0) !== token.substr(-1)) return false;
+  if (['"', "'"].includes(token.charAt(0))) return true;
+  return false;
+};
+
+const isMethodInvocation = (token: string): boolean => {
+  return pipe(tokenizeOnTopLevelParentheses, last, isWrappedInParentheses)(token);
+};
+
+const isClosureInvocation = (token: string): boolean => {
+  return pipe(tokenizeOnTopLevelCurlyBrackets, last, isWrappedInCurlyBrackets)(token);
+};
+
+const trimParentheses = (expression: string): string => expression.slice(1, -1);
+
+const trimCurlyBrackets = (expression: string): string => expression.slice(1, -1);
+
+const getMethodTokenAndArgumentTokensFromMethodInvocation = (
+  token: string,
+): { methodToken: string; argumentTokens: string[] } => {
+  // The word before the first parenthesis is the method name
+  // The token may be a double application of a curried function, so we cannot
+  // assume that the first opening parenthesis is closed by the last closing
+  // parenthesis
+  const tokens = tokenizeOnTopLevelParentheses(token);
+  return {
+    methodToken: tokens.slice(0, -1).join(''),
+    argumentTokens: pipe(trimParentheses, tokenizeOnTopLevelComma)(tokens.slice(-1)[0]),
+  };
+};
+
+const getIndentation = (lineOfCode: string): number => lineOfCode.split('').findIndex(neq(' '));
+
+const getMethodTokenAndClosureCodeBlockFromClosureInvocation = (
+  token: string,
+  fullQuery: string,
+): { methodToken: string; closureCodeBlock: UnformattedClosureCodeBlock } => {
+  // The word before the first curly bracket is the method name
+  // The token may be a double application of a curried function, so we cannot
+  // assume that the first opening curly bracket is closed by the last closing
+  // curly bracket
+  const tokens = tokenizeOnTopLevelCurlyBrackets(token);
+  const methodToken = tokens.slice(0, -1).join('');
+  const closureCodeBlockToken = trimCurlyBrackets(tokens.slice(-1)[0]);
+  const initialClosureCodeBlockIndentation = fullQuery
+    .substr(0, fullQuery.indexOf(closureCodeBlockToken))
+    .split('\n')
+    .slice(-1)[0].length;
+  return {
+    methodToken,
+    closureCodeBlock: trimCurlyBrackets(tokens.slice(-1)[0])
+      .split('\n')
+      .map((lineOfCode, i) => ({
+        lineOfCode: lineOfCode.trimStart(),
+        relativeIndentation:
+          i === 0 ? getIndentation(lineOfCode) : getIndentation(lineOfCode) - initialClosureCodeBlockIndentation,
+      })),
+  };
+};
+
+const parseCodeBlockToSyntaxTree = (fullCode: string, shouldCalculateInitialHorizontalPosition?: boolean) => (
+  codeBlock: string,
+): UnformattedSyntaxTree => {
+  const tokens = tokenizeOnTopLevelPunctuation(codeBlock);
+  if (tokens.length === 1) {
+    const token = tokens[0];
+    if (isMethodInvocation(token)) {
+      const { methodToken, argumentTokens } = getMethodTokenAndArgumentTokensFromMethodInvocation(token);
+      return {
+        type: TokenType.Method,
+        method: parseCodeBlockToSyntaxTree(fullCode)(methodToken),
+        arguments: argumentTokens.map(parseCodeBlockToSyntaxTree(fullCode)),
+      };
+    }
+    if (isClosureInvocation(token)) {
+      const { methodToken, closureCodeBlock } = getMethodTokenAndClosureCodeBlockFromClosureInvocation(token, fullCode);
+      return {
+        type: TokenType.Closure,
+        method: parseCodeBlockToSyntaxTree(fullCode)(methodToken),
+        closureCodeBlock,
+      };
+    }
+    if (isString(token)) {
+      return {
+        type: TokenType.String,
+        string: token,
+      };
+    }
+    return {
+      type: TokenType.Word,
+      word: token,
+    };
+  }
+  return {
+    type: TokenType.Traversal,
+    steps: tokens.map(parseCodeBlockToSyntaxTree(fullCode)),
+    initialHorizontalPosition: shouldCalculateInitialHorizontalPosition
+      ? fullCode.substr(0, fullCode.indexOf(codeBlock)).split('\n').slice(-1)[0].length
+      : 0,
+  };
+};
+
+export const parseNonGremlinCodeToSyntaxTree = (code: string): UnformattedNonGremlinSyntaxTree => ({
+  type: TokenType.NonGremlinCode,
+  code,
+});
+
+export const parseToSyntaxTrees = (code: string): UnformattedSyntaxTree[] => {
+  const queries = extractGremlinQueries(code);
+  const { syntaxTrees, remainingCode } = queries.reduce(
+    (state, query: string): { syntaxTrees: UnformattedSyntaxTree[]; remainingCode: string } => {
+      const indexOfQuery = state.remainingCode.indexOf(query);
+      const nonGremlinCode = state.remainingCode.substr(0, indexOfQuery);
+      return {
+        syntaxTrees: [
+          ...state.syntaxTrees,
+          parseNonGremlinCodeToSyntaxTree(nonGremlinCode),
+          parseCodeBlockToSyntaxTree(code, true)(query),
+        ],
+        remainingCode: state.remainingCode.substr(indexOfQuery + query.length),
+      };
+    },
+    { syntaxTrees: [] as UnformattedSyntaxTree[], remainingCode: code },
+  );
+  if (!remainingCode) return syntaxTrees;
+  return [...syntaxTrees, parseNonGremlinCodeToSyntaxTree(remainingCode)];
+};
diff --git a/gremlint/src/formatQuery/recreateQueryOnelinerFromSyntaxTree.ts b/gremlint/src/formatQuery/recreateQueryOnelinerFromSyntaxTree.ts
new file mode 100644
index 0000000..9075d7e
--- /dev/null
+++ b/gremlint/src/formatQuery/recreateQueryOnelinerFromSyntaxTree.ts
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+import {
+  TokenType,
+  UnformattedClosureSyntaxTree,
+  UnformattedMethodSyntaxTree,
+  UnformattedNonGremlinSyntaxTree,
+  UnformattedStringSyntaxTree,
+  UnformattedTraversalSyntaxTree,
+  UnformattedWordSyntaxTree,
+} from './types';
+import { last, spaces } from './utils';
+
+type GremlinOnelinerSyntaxTree =
+  | UnformattedNonGremlinSyntaxTree
+  | Pick<UnformattedTraversalSyntaxTree, 'type' | 'steps'>
+  | Pick<UnformattedMethodSyntaxTree, 'type' | 'method' | 'arguments'>
+  | Pick<UnformattedClosureSyntaxTree, 'type' | 'method' | 'closureCodeBlock'>
+  | Pick<UnformattedStringSyntaxTree, 'type' | 'string'>
+  | Pick<UnformattedWordSyntaxTree, 'type' | 'word'>;
+
+const recreateQueryOnelinerFromSyntaxTree = (localIndentation: number = 0) => (
+  syntaxTree: GremlinOnelinerSyntaxTree,
+): string => {
+  switch (syntaxTree.type) {
+    // This case will never occur
+    case TokenType.NonGremlinCode:
+      return syntaxTree.code;
+    case TokenType.Traversal:
+      return spaces(localIndentation) + syntaxTree.steps.map(recreateQueryOnelinerFromSyntaxTree()).join('.');
+    case TokenType.Method:
+      return (
+        spaces(localIndentation) +
+        recreateQueryOnelinerFromSyntaxTree()(syntaxTree.method) +
+        '(' +
+        syntaxTree.arguments.map(recreateQueryOnelinerFromSyntaxTree()).join(', ') +
+        ')'
+      );
+    case TokenType.Closure:
+      return (
+        spaces(localIndentation) +
+        recreateQueryOnelinerFromSyntaxTree()(syntaxTree.method) +
+        '{' +
+        last(
+          syntaxTree.closureCodeBlock.map(
+            ({ lineOfCode, relativeIndentation }) => `${spaces(Math.max(relativeIndentation, 0))}${lineOfCode}`,
+          ),
+        ) +
+        '}'
+      );
+    case TokenType.String:
+      return spaces(localIndentation) + syntaxTree.string;
+    case TokenType.Word:
+      return spaces(localIndentation) + syntaxTree.word;
+  }
+};
+
+export default recreateQueryOnelinerFromSyntaxTree;
diff --git a/gremlint/src/formatQuery/recreateQueryStringFromFormattedSyntaxTrees.ts b/gremlint/src/formatQuery/recreateQueryStringFromFormattedSyntaxTrees.ts
new file mode 100644
index 0000000..e7d9f6a
--- /dev/null
+++ b/gremlint/src/formatQuery/recreateQueryStringFromFormattedSyntaxTrees.ts
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+
+import { FormattedSyntaxTree, GremlintInternalConfig, TokenType } from './types';
+import { eq, spaces } from './utils';
+
+const recreateQueryStringFromFormattedSyntaxTree = (syntaxTree: FormattedSyntaxTree): string => {
+  if (syntaxTree.type === TokenType.NonGremlinCode) {
+    return syntaxTree.code;
+  }
+  if (syntaxTree.type === TokenType.Traversal) {
+    return syntaxTree.stepGroups
+      .map((stepGroup) => stepGroup.steps.map(recreateQueryStringFromFormattedSyntaxTree).join('.'))
+      .join('\n');
+  }
+  if (syntaxTree.type === TokenType.Method) {
+    return (
+      (syntaxTree.shouldStartWithDot ? '.' : '') +
+      [
+        recreateQueryStringFromFormattedSyntaxTree(syntaxTree.method) + '(',
+        syntaxTree.argumentGroups
+          .map((args) => args.map(recreateQueryStringFromFormattedSyntaxTree).join(', '))
+          .join(',\n') +
+          ')' +
+          (syntaxTree.shouldEndWithDot ? '.' : ''),
+      ].join(syntaxTree.argumentsShouldStartOnNewLine ? '\n' : '')
+    );
+  }
+  if (syntaxTree.type === TokenType.Closure) {
+    return (
+      (syntaxTree.shouldStartWithDot ? '.' : '') +
+      recreateQueryStringFromFormattedSyntaxTree(syntaxTree.method) +
+      '{' +
+      syntaxTree.closureCodeBlock
+        .map(({ lineOfCode, localIndentation }, i) => `${spaces(localIndentation)}${lineOfCode}`)
+        .join('\n') +
+      '}' +
+      (syntaxTree.shouldEndWithDot ? '.' : '')
+    );
+  }
+  if (syntaxTree.type === TokenType.String) {
+    return spaces(syntaxTree.localIndentation) + syntaxTree.string;
+  }
+  if (syntaxTree.type === TokenType.Word) {
+    return (
+      spaces(syntaxTree.localIndentation) +
+      (syntaxTree.shouldStartWithDot ? '.' : '') +
+      syntaxTree.word +
+      (syntaxTree.shouldEndWithDot ? '.' : '')
+    );
+  }
+  // The following line is just here to convince TypeScript that the return type
+  // is string and not string | undefined.
+  return '';
+};
+
+const withIndentationIfNotEmpty = (indentation: number) => (lineOfCode: string): string => {
+  if (!lineOfCode) return lineOfCode;
+  return spaces(indentation) + lineOfCode;
+};
+
+const lineIsEmpty = (lineOfCode: string): boolean => {
+  return lineOfCode.split('').every(eq(' '));
+};
+
+const removeIndentationFromEmptyLines = (lineOfCode: string): string => {
+  if (lineIsEmpty(lineOfCode)) return '';
+  return lineOfCode;
+};
+
+export const recreateQueryStringFromFormattedSyntaxTrees = ({ globalIndentation }: GremlintInternalConfig) => (
+  syntaxTrees: FormattedSyntaxTree[],
+): string => {
+  return syntaxTrees
+    .map(recreateQueryStringFromFormattedSyntaxTree)
+    .join('')
+    .split('\n')
+    .map(withIndentationIfNotEmpty(globalIndentation))
+    .map(removeIndentationFromEmptyLines)
+    .join('\n');
+};
diff --git a/gremlint/src/formatQuery/types.ts b/gremlint/src/formatQuery/types.ts
new file mode 100644
index 0000000..f85e91a
--- /dev/null
+++ b/gremlint/src/formatQuery/types.ts
@@ -0,0 +1,169 @@
+/*
+ * 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.
+ */
+
+export type GremlintUserConfig = {
+  indentation: number;
+  maxLineLength: number;
+  shouldPlaceDotsAfterLineBreaks: boolean;
+};
+
+export type GremlintInternalConfig = {
+  globalIndentation: number;
+  localIndentation: number;
+  maxLineLength: number;
+  shouldPlaceDotsAfterLineBreaks: boolean;
+  shouldStartWithDot: boolean;
+  shouldEndWithDot: boolean;
+  horizontalPosition: number; // Will be used by child syntax trees and is the horizontal position its child content starts, so a non-indented hasLabel(...) has a horizontal position of 9
+};
+
+export enum TokenType {
+  NonGremlinCode = 'NON_GREMLIN_CODE',
+  Traversal = 'TRAVERSAL',
+  Method = 'METHOD',
+  Closure = 'CLOSURE',
+  String = 'STRING',
+  Word = 'WORD',
+}
+
+export type UnformattedNonGremlinSyntaxTree = {
+  type: TokenType.NonGremlinCode;
+  code: string;
+};
+
+export type UnformattedTraversalSyntaxTree = {
+  type: TokenType.Traversal;
+  steps: UnformattedSyntaxTree[];
+  // Initial horizontal position of the first line of the query. This is needed in order to be able to preserve relative
+  // indentation between lines inside a non-Gremlin code block that starts on the first line of the query.
+  initialHorizontalPosition: number;
+};
+
+export type UnformattedMethodSyntaxTree = {
+  type: TokenType.Method;
+  method: UnformattedSyntaxTree;
+  arguments: UnformattedSyntaxTree[];
+};
+
+export type UnformattedClosureLineOfCode = {
+  lineOfCode: string;
+  // Relative indentation compared to the opening curly bracket, so relativeIndentation of In {it.get} is 0.
+  relativeIndentation: number;
+};
+
+export type UnformattedClosureCodeBlock = UnformattedClosureLineOfCode[];
+
+export type UnformattedClosureSyntaxTree = {
+  type: TokenType.Closure;
+  method: UnformattedSyntaxTree;
+  closureCodeBlock: UnformattedClosureCodeBlock;
+};
+
+export type UnformattedStringSyntaxTree = {
+  type: TokenType.String;
+  string: string;
+};
+
+export type UnformattedWordSyntaxTree = {
+  type: TokenType.Word;
+  word: string;
+};
+
+export type UnformattedSyntaxTree =
+  | UnformattedMethodSyntaxTree
+  | UnformattedClosureSyntaxTree
+  | UnformattedStringSyntaxTree
+  | UnformattedWordSyntaxTree
+  | UnformattedTraversalSyntaxTree
+  | UnformattedNonGremlinSyntaxTree;
+
+export type FormattedNonGremlinSyntaxTree = UnformattedNonGremlinSyntaxTree & {
+  width: number;
+};
+
+export type GremlinStepGroup = {
+  steps: FormattedSyntaxTree[];
+};
+
+export type FormattedTraversalSyntaxTree = {
+  type: TokenType.Traversal;
+  steps: UnformattedSyntaxTree[];
+  stepGroups: GremlinStepGroup[];
+  initialHorizontalPosition: number;
+  localIndentation: number;
+  width: number;
+};
+
+export type FormattedMethodSyntaxTree = {
+  type: TokenType.Method;
+  method: FormattedSyntaxTree;
+  arguments: UnformattedSyntaxTree[];
+  argumentGroups: FormattedSyntaxTree[][];
+  argumentsShouldStartOnNewLine: boolean;
+  localIndentation: number;
+  width: number;
+  shouldStartWithDot: boolean;
+  shouldEndWithDot: boolean;
+};
+
+type FormattedClosureLineOfCode = {
+  lineOfCode: string;
+  relativeIndentation: number;
+  localIndentation: number;
+};
+
+type FormattedClosureCodeBlock = FormattedClosureLineOfCode[];
+
+export type FormattedClosureSyntaxTree = {
+  type: TokenType.Closure;
+  method: FormattedSyntaxTree;
+  closureCodeBlock: FormattedClosureCodeBlock;
+  localIndentation: number;
+  width: number;
+  shouldStartWithDot: boolean;
+  shouldEndWithDot: boolean;
+};
+
+export type FormattedStringSyntaxTree = {
+  type: TokenType.String;
+  string: string;
+  width: number;
+  localIndentation: number;
+};
+
+export type FormattedWordSyntaxTree = {
+  type: TokenType.Word;
+  word: string;
+  localIndentation: number;
+  width: number;
+  shouldStartWithDot: boolean;
+  shouldEndWithDot: boolean;
+};
+
+export type FormattedSyntaxTree =
+  | FormattedTraversalSyntaxTree
+  | FormattedMethodSyntaxTree
+  | FormattedClosureSyntaxTree
+  | FormattedStringSyntaxTree
+  | FormattedWordSyntaxTree
+  | FormattedNonGremlinSyntaxTree;
+
+export type GremlinSyntaxTreeFormatter = (
+  config: GremlintInternalConfig,
+) => (syntaxTree: UnformattedSyntaxTree) => FormattedSyntaxTree;
diff --git a/gremlint/src/formatQuery/utils.ts b/gremlint/src/formatQuery/utils.ts
new file mode 100644
index 0000000..4651759
--- /dev/null
+++ b/gremlint/src/formatQuery/utils.ts
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+export const last = <T>(array: T[]): T | undefined => array.slice(-1)[0];
+
+export const pipe = (...fns: ((value: any) => any)[]) => (value: any) => fns.reduce((value, fn) => fn(value), value);
+
+export const spaces = (numberOfSpaces: number): string => Array(numberOfSpaces + 1).join(' ');
+
+export const eq = (a: unknown) => (b: unknown): boolean => a === b;
+
+export const neq = (a: unknown) => (b: unknown): boolean => a !== b;
+
+export const sum = (a: number, b: number): number => a + b;
+
+export const count = (array: any): number => array?.length ?? 0;
+
+export const choose = (
+  getCondition: (...params: any[]) => any,
+  getThen: (...params: any[]) => any,
+  getElse: (...params: any[]) => any,
+) => (...params: any[]) => {
+  return getCondition(...params) ? getThen(...params) : getElse(...params);
+};
diff --git a/gremlint/src/index.ts b/gremlint/src/index.ts
new file mode 100644
index 0000000..26da959
--- /dev/null
+++ b/gremlint/src/index.ts
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+export { formatQuery } from './formatQuery';
diff --git a/gremlint/tsconfig.json b/gremlint/tsconfig.json
new file mode 100644
index 0000000..797ad94
--- /dev/null
+++ b/gremlint/tsconfig.json
@@ -0,0 +1,12 @@
+{
+  "compilerOptions": {
+    "target": "es5",
+    "module": "commonjs",
+    "declaration": true,
+    "outDir": "./lib",
+    "strict": true,
+    "lib": ["DOM", "ES2017"]
+  },
+  "include": ["src"],
+  "exclude": ["node_modules", "**/__tests__/*"]
+}
diff --git a/gremlint/tslint.json b/gremlint/tslint.json
new file mode 100644
index 0000000..5761be8
--- /dev/null
+++ b/gremlint/tslint.json
@@ -0,0 +1,6 @@
+{
+  "extends": ["tslint:recommended", "tslint-config-prettier"],
+  "rules": {
+    "no-shadowed-variable": false
+  }
+}
diff --git a/hadoop-gremlin/pom.xml b/hadoop-gremlin/pom.xml
index 16a13a1..86ed1e9 100644
--- a/hadoop-gremlin/pom.xml
+++ b/hadoop-gremlin/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.apache.tinkerpop</groupId>
         <artifactId>tinkerpop</artifactId>
-        <version>3.4.12-SNAPSHOT</version>
+        <version>3.5.1-SNAPSHOT</version>
     </parent>
     <artifactId>hadoop-gremlin</artifactId>
     <name>Apache TinkerPop :: Hadoop Gremlin</name>
@@ -100,30 +100,47 @@
                     <artifactId>servlet-api</artifactId>
                 </exclusion>
                 <exclusion>
+                    <groupId>commons-lang</groupId>
+                    <artifactId>commons-lang</artifactId>
+                </exclusion>
+                <exclusion>
                     <groupId>org.apache.commons</groupId>
                     <artifactId>commons-compress</artifactId>
                 </exclusion>
+                <!--
+                spark 3.0/scala 2.12 uses paranamer 2.8 and hadoop is stuck with an older version. without 2.8 you get
+                SPARK-14220
+                -->
+                <exclusion>
+                    <groupId>com.thoughtworks.paranamer</groupId>
+                    <artifactId>paranamer</artifactId>
+                </exclusion>
             </exclusions>
             <!--<scope>provided</scope>-->
         </dependency>
         <!-- consistent dependencies -->
         <dependency>
+            <groupId>com.thoughtworks.paranamer</groupId>
+            <artifactId>paranamer</artifactId>
+            <version>2.8</version>
+        </dependency>
+        <dependency>
             <groupId>commons-io</groupId>
             <artifactId>commons-io</artifactId>
         </dependency>
         <dependency>
+            <groupId>commons-lang</groupId>
+            <artifactId>commons-lang</artifactId>
+            <version>2.6</version>
+        </dependency>
+        <dependency>
             <groupId>commons-codec</groupId>
             <artifactId>commons-codec</artifactId>
         </dependency>
         <dependency>
             <groupId>commons-logging</groupId>
             <artifactId>commons-logging</artifactId>
-            <version>1.1.3</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.commons</groupId>
-            <artifactId>commons-compress</artifactId>
-            <version>1.19</version>
+            <version>1.2</version>
         </dependency>
         <dependency>
             <groupId>com.google.guava</groupId>
diff --git a/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/process/computer/HadoopCombine.java b/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/process/computer/HadoopCombine.java
index 06778e6..052cae6 100644
--- a/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/process/computer/HadoopCombine.java
+++ b/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/process/computer/HadoopCombine.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.hadoop.process.computer;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.hadoop.mapreduce.Reducer;
 import org.apache.tinkerpop.gremlin.hadoop.structure.HadoopGraph;
 import org.apache.tinkerpop.gremlin.hadoop.structure.io.HadoopPools;
diff --git a/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/process/computer/HadoopMap.java b/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/process/computer/HadoopMap.java
index 5fc7026..93a86c0 100644
--- a/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/process/computer/HadoopMap.java
+++ b/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/process/computer/HadoopMap.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.hadoop.process.computer;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.hadoop.io.NullWritable;
 import org.apache.hadoop.mapreduce.Mapper;
 import org.apache.tinkerpop.gremlin.hadoop.structure.HadoopGraph;
diff --git a/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/process/computer/HadoopReduce.java b/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/process/computer/HadoopReduce.java
index 6ca7b8f..8b4eda5 100644
--- a/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/process/computer/HadoopReduce.java
+++ b/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/process/computer/HadoopReduce.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.hadoop.process.computer;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.hadoop.mapreduce.Reducer;
 import org.apache.tinkerpop.gremlin.hadoop.structure.HadoopGraph;
 import org.apache.tinkerpop.gremlin.hadoop.structure.io.HadoopPools;
diff --git a/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/process/computer/util/MapReduceHelper.java b/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/process/computer/util/MapReduceHelper.java
index 88474b2..f449581 100644
--- a/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/process/computer/util/MapReduceHelper.java
+++ b/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/process/computer/util/MapReduceHelper.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.hadoop.process.computer.util;
 
-import org.apache.commons.configuration.BaseConfiguration;
+import org.apache.commons.configuration2.BaseConfiguration;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.fs.Path;
@@ -65,7 +65,6 @@
             newConfiguration.unset(Constants.GREMLIN_HADOOP_GRAPH_FILTER);
         }
         final BaseConfiguration apacheConfiguration = new BaseConfiguration();
-        apacheConfiguration.setDelimiterParsingDisabled(true);
         mapReduce.storeState(apacheConfiguration);
         ConfUtil.mergeApacheIntoHadoopConfiguration(apacheConfiguration, newConfiguration);
 
diff --git a/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/HadoopConfiguration.java b/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/HadoopConfiguration.java
index a8125ea..610f073 100644
--- a/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/HadoopConfiguration.java
+++ b/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/HadoopConfiguration.java
@@ -18,13 +18,9 @@
  */
 package org.apache.tinkerpop.gremlin.hadoop.structure;
 
-import org.apache.commons.configuration.AbstractConfiguration;
-import org.apache.commons.configuration.Configuration;
-import org.apache.hadoop.io.NullWritable;
-import org.apache.hadoop.mapreduce.InputFormat;
-import org.apache.hadoop.mapreduce.OutputFormat;
+import org.apache.commons.configuration2.AbstractConfiguration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.hadoop.Constants;
-import org.apache.tinkerpop.gremlin.hadoop.structure.io.VertexWritable;
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 import org.javatuples.Pair;
 
@@ -42,7 +38,6 @@
 
     public HadoopConfiguration() {
         super();
-        super.setDelimiterParsingDisabled(true);
     }
 
     public HadoopConfiguration(final Configuration configuration) {
@@ -51,6 +46,26 @@
     }
 
     @Override
+    protected Iterator<String> getKeysInternal() {
+        return properties.keySet().iterator();
+    }
+
+    @Override
+    protected Object getPropertyInternal(final String s) {
+        return properties.get(s);
+    }
+
+    @Override
+    protected boolean isEmptyInternal() {
+        return properties.isEmpty();
+    }
+
+    @Override
+    protected boolean containsKeyInternal(String s) {
+        return properties.containsKey(s);
+    }
+
+    @Override
     protected void addPropertyDirect(final String key, final Object value) {
         this.properties.put(key, value);
     }
@@ -60,26 +75,6 @@
         this.properties.remove(key);
     }
 
-    @Override
-    public boolean isEmpty() {
-        return this.properties.isEmpty();
-    }
-
-    @Override
-    public boolean containsKey(final String key) {
-        return this.properties.containsKey(key);
-    }
-
-    @Override
-    public Object getProperty(final String key) {
-        return this.properties.get(key);
-    }
-
-    @Override
-    public Iterator<String> getKeys() {
-        return this.properties.keySet().iterator();
-    }
-
     ///////
 
     public <A> Class<A> getGraphReader() {
diff --git a/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/HadoopGraph.java b/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/HadoopGraph.java
index 9ec0cfd..f4722ea 100644
--- a/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/HadoopGraph.java
+++ b/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/HadoopGraph.java
@@ -18,10 +18,10 @@
  */
 package org.apache.tinkerpop.gremlin.hadoop.structure;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.ConfigurationException;
-import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.configuration2.builder.fluent.Configurations;
+import org.apache.commons.configuration2.ex.ConfigurationException;
 import org.apache.tinkerpop.gremlin.hadoop.Constants;
 import org.apache.tinkerpop.gremlin.hadoop.process.computer.AbstractHadoopGraphComputer;
 import org.apache.tinkerpop.gremlin.hadoop.process.computer.traversal.strategy.HadoopIoStrategy;
@@ -188,7 +188,8 @@
 
     public static HadoopGraph open(final String configurationFile) throws ConfigurationException {
         if (null == configurationFile) throw Graph.Exceptions.argumentCanNotBeNull("configurationFile");
-        return open(new PropertiesConfiguration(configurationFile));
+        final Configurations configs = new Configurations();
+        return open(configs.properties(configurationFile));
     }
 
     @Override
diff --git a/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/io/FileSystemStorage.java b/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/io/FileSystemStorage.java
index b0847f1..e718f20 100644
--- a/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/io/FileSystemStorage.java
+++ b/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/io/FileSystemStorage.java
@@ -19,7 +19,7 @@
 
 package org.apache.tinkerpop.gremlin.hadoop.structure.io;
 
-import org.apache.commons.configuration.BaseConfiguration;
+import org.apache.commons.configuration2.BaseConfiguration;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.FSDataInputStream;
 import org.apache.hadoop.fs.FSDataOutputStream;
@@ -181,7 +181,7 @@
 
     @Override
     public Iterator<Vertex> head(final String location, final Class readerClass, final int totalLines) {
-        final org.apache.commons.configuration.Configuration configuration = new BaseConfiguration();
+        final org.apache.commons.configuration2.Configuration configuration = new BaseConfiguration();
         configuration.setProperty(Constants.GREMLIN_HADOOP_INPUT_LOCATION, Constants.getSearchGraphLocation(location, this).get());
         configuration.setProperty(Constants.GREMLIN_HADOOP_GRAPH_READER, readerClass.getCanonicalName());
         try {
diff --git a/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/io/GraphFilterAware.java b/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/io/GraphFilterAware.java
index ff28d86..cbf735b 100644
--- a/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/io/GraphFilterAware.java
+++ b/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/io/GraphFilterAware.java
@@ -19,7 +19,7 @@
 
 package org.apache.tinkerpop.gremlin.hadoop.structure.io;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.hadoop.Constants;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
 import org.apache.tinkerpop.gremlin.process.computer.GraphFilter;
diff --git a/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/io/HadoopPoolShimService.java b/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/io/HadoopPoolShimService.java
index db79d97..40c73a2 100644
--- a/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/io/HadoopPoolShimService.java
+++ b/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/io/HadoopPoolShimService.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.hadoop.structure.io;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.structure.io.gryo.kryoshim.KryoShimService;
 import org.apache.tinkerpop.shaded.kryo.io.Input;
 import org.apache.tinkerpop.shaded.kryo.io.Output;
diff --git a/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/io/HadoopPools.java b/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/io/HadoopPools.java
index ea73431..69f176f 100644
--- a/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/io/HadoopPools.java
+++ b/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/io/HadoopPools.java
@@ -18,8 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.hadoop.structure.io;
 
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.ConfigurationUtils;
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.configuration2.ConfigurationUtils;
 import org.apache.tinkerpop.gremlin.hadoop.structure.HadoopGraph;
 import org.apache.tinkerpop.gremlin.hadoop.structure.util.ConfUtil;
 import org.apache.tinkerpop.gremlin.structure.io.IoRegistry;
diff --git a/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/io/InputOutputHelper.java b/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/io/InputOutputHelper.java
index ebb9f77..381c784 100644
--- a/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/io/InputOutputHelper.java
+++ b/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/io/InputOutputHelper.java
@@ -18,8 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.hadoop.structure.io;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.hadoop.io.NullWritable;
 import org.apache.hadoop.mapreduce.InputFormat;
 import org.apache.hadoop.mapreduce.OutputFormat;
diff --git a/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/io/ObjectWritableComparator.java b/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/io/ObjectWritableComparator.java
index 976518f..e2884cc 100644
--- a/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/io/ObjectWritableComparator.java
+++ b/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/io/ObjectWritableComparator.java
@@ -64,7 +64,7 @@
         @Override
         public void setConf(final Configuration configuration) {
             super.setConf(configuration);
-            final org.apache.commons.configuration.Configuration apacheConfiguration = ConfUtil.makeApacheConfiguration(configuration);
+            final org.apache.commons.configuration2.Configuration apacheConfiguration = ConfUtil.makeApacheConfiguration(configuration);
             this.comparator = MapReduce.<MapReduce<?,?,?,?,?>>createMapReduce(HadoopGraph.open(apacheConfiguration),apacheConfiguration).getMapKeySort().get();
         }
     }
@@ -73,7 +73,7 @@
         @Override
         public void setConf(final Configuration configuration) {
             super.setConf(configuration);
-            final org.apache.commons.configuration.Configuration apacheConfiguration = ConfUtil.makeApacheConfiguration(configuration);
+            final org.apache.commons.configuration2.Configuration apacheConfiguration = ConfUtil.makeApacheConfiguration(configuration);
             this.comparator = MapReduce.<MapReduce<?,?,?,?,?>>createMapReduce(HadoopGraph.open(apacheConfiguration),apacheConfiguration).getReduceKeySort().get();
         }
     }
diff --git a/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/util/ConfUtil.java b/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/util/ConfUtil.java
index 0e1efb7..b5685ea 100644
--- a/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/util/ConfUtil.java
+++ b/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/util/ConfUtil.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.hadoop.structure.util;
 
-import org.apache.commons.configuration.BaseConfiguration;
+import org.apache.commons.configuration2.BaseConfiguration;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.io.NullWritable;
 import org.apache.hadoop.mapreduce.InputFormat;
@@ -33,14 +33,13 @@
     private ConfUtil() {
     }
 
-    public static org.apache.commons.configuration.Configuration makeApacheConfiguration(final Configuration hadoopConfiguration) {
+    public static org.apache.commons.configuration2.Configuration makeApacheConfiguration(final Configuration hadoopConfiguration) {
         final BaseConfiguration apacheConfiguration = new BaseConfiguration();
-        apacheConfiguration.setDelimiterParsingDisabled(true);
         hadoopConfiguration.iterator().forEachRemaining(e -> apacheConfiguration.setProperty(e.getKey(), e.getValue()));
         return apacheConfiguration;
     }
 
-    public static Configuration makeHadoopConfiguration(final org.apache.commons.configuration.Configuration apacheConfiguration) {
+    public static Configuration makeHadoopConfiguration(final org.apache.commons.configuration2.Configuration apacheConfiguration) {
         final Configuration hadoopConfiguration = new Configuration();
         apacheConfiguration.getKeys().forEachRemaining(key -> {
             final Object object = apacheConfiguration.getProperty(key);
@@ -49,7 +48,7 @@
         return hadoopConfiguration;
     }
 
-    public static void mergeApacheIntoHadoopConfiguration(final org.apache.commons.configuration.Configuration apacheConfiguration, final Configuration hadoopConfiguration) {
+    public static void mergeApacheIntoHadoopConfiguration(final org.apache.commons.configuration2.Configuration apacheConfiguration, final Configuration hadoopConfiguration) {
         apacheConfiguration.getKeys().forEachRemaining(key -> {
             final Object object = apacheConfiguration.getProperty(key);
             hadoopConfiguration.set(key, object.toString());
diff --git a/neo4j-gremlin/pom.xml b/neo4j-gremlin/pom.xml
index 743a487..a0299ce 100644
--- a/neo4j-gremlin/pom.xml
+++ b/neo4j-gremlin/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.apache.tinkerpop</groupId>
         <artifactId>tinkerpop</artifactId>
-        <version>3.4.12-SNAPSHOT</version>
+        <version>3.5.1-SNAPSHOT</version>
     </parent>
     <artifactId>neo4j-gremlin</artifactId>
     <name>Apache TinkerPop :: Neo4j Gremlin</name>
@@ -34,7 +34,7 @@
         <dependency>
             <groupId>org.neo4j</groupId>
             <artifactId>neo4j-tinkerpop-api</artifactId>
-            <version>0.1</version>
+            <version>0.1.1</version>
         </dependency>
         <!-- TESTING -->
         <dependency>
@@ -42,6 +42,13 @@
             <artifactId>gremlin-test</artifactId>
             <version>${project.version}</version>
             <scope>test</scope>
+            <!-- conflict from kirby -->
+            <exclusions>
+                <exclusion>
+                    <groupId>org.ow2.asm</groupId>
+                    <artifactId>asm</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
@@ -89,7 +96,7 @@
                 <configuration>
                     <archive>
                         <manifestEntries>
-                            <Gremlin-Plugin-Dependencies>org.neo4j:neo4j-tinkerpop-api-impl:0.7-3.2.3
+                            <Gremlin-Plugin-Dependencies>org.neo4j:neo4j-tinkerpop-api-impl:0.9-3.4.0
                             </Gremlin-Plugin-Dependencies>
                         </manifestEntries>
                     </archive>
@@ -117,7 +124,7 @@
                 <dependency>
                     <groupId>org.neo4j</groupId>
                     <artifactId>neo4j-tinkerpop-api-impl</artifactId>
-                    <version>0.7-3.2.3</version>
+                    <version>0.9-3.4.0</version>
                     <scope>test</scope>
                     <exclusions>
                         <exclusion>
@@ -129,6 +136,10 @@
                             <artifactId>commons-lang3</artifactId>
                         </exclusion>
                         <exclusion>
+                            <groupId>org.apache.commons</groupId>
+                            <artifactId>commons-text</artifactId>
+                        </exclusion>
+                        <exclusion>
                             <groupId>com.github.ben-manes.caffeine</groupId>
                             <artifactId>caffeine</artifactId>
                         </exclusion>
@@ -148,9 +159,22 @@
                             <groupId>org.slf4j</groupId>
                             <artifactId>slf4j-nop</artifactId>
                         </exclusion>
+                        <exclusion>
+                            <groupId>org.apache.lucene</groupId>
+                            <artifactId>lucene-core</artifactId>
+                        </exclusion>
+                        <exclusion>
+                            <groupId>io.dropwizard.metrics</groupId>
+                            <artifactId>metrics-core</artifactId>
+                        </exclusion>
                     </exclusions>
                 </dependency>
                 <dependency>
+                    <groupId>org.apache.commons</groupId>
+                    <artifactId>commons-text</artifactId>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
                     <groupId>org.scala-lang</groupId>
                     <artifactId>scala-library</artifactId>
                     <version>2.11.8</version>
@@ -168,11 +192,22 @@
                     <version>2.3.1</version>
                     <scope>test</scope>
                 </dependency>
-                <!-- self-conflict with neo4j-graph-matching -->
+                <dependency>
+                    <groupId>org.apache.lucene</groupId>
+                    <artifactId>lucene-core</artifactId>
+                    <version>5.5.0</version>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>io.dropwizard.metrics</groupId>
+                    <artifactId>metrics-core</artifactId>
+                    <version>4.0.2</version>
+                    <scope>test</scope>
+                </dependency>
                 <dependency>
                     <groupId>org.neo4j</groupId>
                     <artifactId>neo4j-kernel</artifactId>
-                    <version>3.2.3</version>
+                    <version>3.4.11</version>
                     <scope>test</scope>
                 </dependency>
                 <!-- *** WARNING *** -->
diff --git a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/process/traversal/step/sideEffect/Neo4jGraphStep.java b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/process/traversal/step/sideEffect/Neo4jGraphStep.java
index f196a8d..43dcd39 100644
--- a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/process/traversal/step/sideEffect/Neo4jGraphStep.java
+++ b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/process/traversal/step/sideEffect/Neo4jGraphStep.java
@@ -18,23 +18,33 @@
  */
 package org.apache.tinkerpop.gremlin.neo4j.process.traversal.step.sideEffect;
 
+import org.apache.tinkerpop.gremlin.neo4j.process.traversal.LabelP;
 import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph;
+import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jVertex;
+import org.apache.tinkerpop.gremlin.process.traversal.Compare;
 import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.Text;
 import org.apache.tinkerpop.gremlin.process.traversal.step.HasContainerHolder;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.GraphStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer;
 import org.apache.tinkerpop.gremlin.process.traversal.util.AndP;
 import org.apache.tinkerpop.gremlin.structure.Edge;
 import org.apache.tinkerpop.gremlin.structure.Element;
+import org.apache.tinkerpop.gremlin.structure.T;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
+import org.neo4j.tinkerpop.api.Neo4jGraphAPI;
+import org.neo4j.tinkerpop.api.Neo4jNode;
+import org.neo4j.tinkerpop.api.Neo4jStringSearchMode;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Optional;
+import java.util.function.BiPredicate;
 
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
@@ -61,7 +71,59 @@
         if (null == this.ids)
             return Collections.emptyIterator();
         final Neo4jGraph graph = (Neo4jGraph) this.getTraversal().getGraph().get();
-        return graph.getTrait().lookupVertices(graph, this.hasContainers, this.ids);
+
+        // ids are present, filter on them first
+        if (ids.length > 0)
+            return IteratorUtils.filter(graph.vertices(ids), vertex -> HasContainer.testAll(vertex, hasContainers));
+        ////// do index lookups //////
+        graph.tx().readWrite();
+        // get a label being search on
+        Optional<String> label = hasContainers.stream()
+                .filter(hasContainer -> hasContainer.getKey().equals(T.label.getAccessor()))
+                .filter(hasContainer -> Compare.eq == hasContainer.getBiPredicate())
+                .map(hasContainer -> (String) hasContainer.getValue())
+                .findAny();
+        if (!label.isPresent())
+            label = hasContainers.stream()
+                    .filter(hasContainer -> hasContainer.getKey().equals(T.label.getAccessor()))
+                    .filter(hasContainer -> hasContainer.getPredicate() instanceof LabelP)
+                    .map(hasContainer -> (String) hasContainer.getValue())
+                    .findAny();
+
+        if (label.isPresent()) {
+            // find a vertex by label and key/value
+            String labelValue = label.get();
+            Neo4jGraphAPI baseGraph = graph.getBaseGraph();
+            for (final HasContainer hasContainer : hasContainers) {
+                String key = hasContainer.getKey();
+                Object value = hasContainer.getValue();
+                if (!key.equals(T.label.getAccessor()) && baseGraph.hasSchemaIndex(labelValue, key)) {
+                    BiPredicate<?, ?> predicate = hasContainer.getBiPredicate();
+                    Iterable<Neo4jNode> nodes = null;
+                    if (Compare.eq == predicate) {
+                        nodes = baseGraph.findNodes(labelValue, key, value);
+                    } else if (Text.containing == predicate) {
+                        nodes = baseGraph.findNodes(labelValue, key, value.toString(), Neo4jStringSearchMode.CONTAINS);
+                    } else if (Text.startingWith == predicate) {
+                        nodes = baseGraph.findNodes(labelValue, key, value.toString(), Neo4jStringSearchMode.PREFIX);
+                    } else if (Text.endingWith == predicate) {
+                        nodes = baseGraph.findNodes(labelValue, key, value.toString(), Neo4jStringSearchMode.SUFFIX);
+                    }
+                    if (nodes != null) {
+                        return IteratorUtils.stream(nodes)
+                                .map(node -> (Vertex) new Neo4jVertex(node, graph))
+                                .filter(vertex -> HasContainer.testAll(vertex, hasContainers)).iterator();
+                    }
+                }
+            }
+            // find a vertex by label
+            return IteratorUtils.stream(graph.getBaseGraph().findNodes(label.get()))
+                    .map(node -> (Vertex) new Neo4jVertex(node, graph))
+                    .filter(vertex -> HasContainer.testAll(vertex, hasContainers)).iterator();
+        } else {
+            // linear scan
+            return IteratorUtils.filter(graph.vertices(), vertex -> HasContainer.testAll(vertex, hasContainers));
+        }
     }
 
     @Override
diff --git a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jEdge.java b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jEdge.java
index 29ccef1..08282fc 100644
--- a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jEdge.java
+++ b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jEdge.java
@@ -115,6 +115,12 @@
     @Override
     public <V> Property<V> property(final String key, final V value) {
         ElementHelper.validateProperty(key, value);
+        
+        if (null == value) {
+            properties(key).forEachRemaining(Property::remove);
+            return Property.empty();
+        }
+
         this.graph.tx().readWrite();
         try {
             this.baseElement.setProperty(key, value);
diff --git a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jGraph.java b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jGraph.java
index aeeb9ef..55be5f6 100644
--- a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jGraph.java
+++ b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jGraph.java
@@ -18,15 +18,12 @@
  */
 package org.apache.tinkerpop.gremlin.neo4j.structure;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.ConfigurationConverter;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.configuration2.ConfigurationConverter;
 import org.apache.tinkerpop.gremlin.neo4j.process.traversal.step.sideEffect.CypherStartStep;
 import org.apache.tinkerpop.gremlin.neo4j.process.traversal.strategy.optimization.Neo4jGraphStepStrategy;
 import org.apache.tinkerpop.gremlin.neo4j.process.util.Neo4jCypherIterator;
-import org.apache.tinkerpop.gremlin.neo4j.structure.trait.MultiMetaNeo4jTrait;
-import org.apache.tinkerpop.gremlin.neo4j.structure.trait.Neo4jTrait;
-import org.apache.tinkerpop.gremlin.neo4j.structure.trait.NoMultiNoMetaNeo4jTrait;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal;
@@ -44,17 +41,11 @@
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 import org.neo4j.tinkerpop.api.Neo4jFactory;
 import org.neo4j.tinkerpop.api.Neo4jGraphAPI;
-import org.neo4j.tinkerpop.api.Neo4jNode;
-import org.neo4j.tinkerpop.api.Neo4jRelationship;
 import org.neo4j.tinkerpop.api.Neo4jTx;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.Map;
-import java.util.Optional;
-import java.util.function.Predicate;
 import java.util.stream.Stream;
 
 /**
@@ -68,8 +59,6 @@
 @Graph.OptIn("org.apache.tinkerpop.gremlin.neo4j.NativeNeo4jSuite")
 public final class Neo4jGraph implements Graph, WrappedGraph<Neo4jGraphAPI> {
 
-    public static final Logger LOGGER = LoggerFactory.getLogger(Neo4jGraph.class);
-
     static {
         TraversalStrategies.GlobalCache.registerStrategies(Neo4jGraph.class, TraversalStrategies.GlobalCache.getStrategies(Graph.class).clone().addStrategies(Neo4jGraphStepStrategy.instance()));
     }
@@ -86,42 +75,13 @@
     public static final String CONFIG_DIRECTORY = "gremlin.neo4j.directory";
     public static final String CONFIG_CONF = "gremlin.neo4j.conf";
 
-    /**
-     * @deprecated As of release 3.3.8, not replaced.
-     */
-    @Deprecated
-    public static final String CONFIG_META_PROPERTIES = "gremlin.neo4j.metaProperties";
-
-    /**
-     * @deprecated As of release 3.3.8, not replaced.
-     */
-    @Deprecated
-    public static final String CONFIG_MULTI_PROPERTIES = "gremlin.neo4j.multiProperties";
-
     private final Neo4jTransaction neo4jTransaction = new Neo4jTransaction();
     private Neo4jGraphVariables neo4jGraphVariables;
 
-    protected Neo4jTrait trait;
-
     private void initialize(final Neo4jGraphAPI baseGraph, final Configuration configuration) {
         this.configuration.copy(configuration);
         this.baseGraph = baseGraph;
         this.neo4jGraphVariables = new Neo4jGraphVariables(this);
-        this.tx().readWrite();
-        final Optional<Boolean> hasMultiProperties = this.neo4jGraphVariables.get(Graph.Hidden.hide(CONFIG_MULTI_PROPERTIES));
-        final Optional<Boolean> hasMetaProperties = this.neo4jGraphVariables.get(Graph.Hidden.hide(CONFIG_META_PROPERTIES));
-        boolean supportsMetaProperties = hasMetaProperties.orElse(this.configuration.getBoolean(CONFIG_META_PROPERTIES, false));
-        boolean supportsMultiProperties = hasMultiProperties.orElse(this.configuration.getBoolean(CONFIG_MULTI_PROPERTIES, false));
-        if (supportsMultiProperties != supportsMetaProperties)
-            throw new IllegalArgumentException(this.getClass().getSimpleName() + " currently supports either both meta-properties and multi-properties or neither");
-        if (!hasMultiProperties.isPresent())
-            this.neo4jGraphVariables.set(Graph.Hidden.hide(CONFIG_MULTI_PROPERTIES), supportsMultiProperties);
-        if (!hasMetaProperties.isPresent())
-            this.neo4jGraphVariables.set(Graph.Hidden.hide(CONFIG_META_PROPERTIES), supportsMetaProperties);
-        this.trait = supportsMultiProperties ? MultiMetaNeo4jTrait.instance() : NoMultiNoMetaNeo4jTrait.instance();
-        if (supportsMultiProperties)
-            LOGGER.warn(this.getClass().getSimpleName() + " multi/meta-properties feature has always been considered experimental and not production ready - it is now deprecated as of 3.3.8");
-        this.tx().commit();
     }
 
     protected Neo4jGraph(final Neo4jGraphAPI baseGraph, final Configuration configuration) {
@@ -179,10 +139,8 @@
     @Override
     public Iterator<Vertex> vertices(final Object... vertexIds) {
         this.tx().readWrite();
-        final Predicate<Neo4jNode> nodePredicate = this.trait.getNodePredicate();
         if (0 == vertexIds.length) {
             return IteratorUtils.stream(this.getBaseGraph().allNodes())
-                    .filter(nodePredicate)
                     .map(node -> (Vertex) new Neo4jVertex(node, this)).iterator();
         } else {
             ElementHelper.validateMixedElementIds(Vertex.class, vertexIds);
@@ -205,7 +163,6 @@
                             throw e;
                         }
                     })
-                    .filter(nodePredicate)
                     .map(node -> (Vertex) new Neo4jVertex(node, this)).iterator();
         }
     }
@@ -213,10 +170,8 @@
     @Override
     public Iterator<Edge> edges(final Object... edgeIds) {
         this.tx().readWrite();
-        final Predicate<Neo4jRelationship> relationshipPredicate = this.trait.getRelationshipPredicate();
         if (0 == edgeIds.length) {
             return IteratorUtils.stream(this.getBaseGraph().allRelationships())
-                    .filter(relationshipPredicate)
                     .map(relationship -> (Edge) new Neo4jEdge(relationship, this)).iterator();
         } else {
             ElementHelper.validateMixedElementIds(Edge.class, edgeIds);
@@ -239,20 +194,10 @@
                             throw e;
                         }
                     })
-                    .filter(relationshipPredicate)
                     .map(relationship -> (Edge) new Neo4jEdge(relationship, this)).iterator();
         }
     }
 
-
-    /**
-     * @deprecated As of release 3.3.8, not replaced.
-     */
-    @Deprecated
-    public Neo4jTrait getTrait() {
-        return this.trait;
-    }
-
     @Override
     public <C extends GraphComputer> C compute(final Class<C> graphComputerClass) {
         throw Graph.Exceptions.graphComputerNotSupported();
@@ -434,12 +379,12 @@
 
             @Override
             public boolean supportsMetaProperties() {
-                return trait.supportsMetaProperties();
+                return false;
             }
 
             @Override
             public boolean supportsMultiProperties() {
-                return trait.supportsMultiProperties();
+                return false;
             }
 
             @Override
@@ -449,7 +394,7 @@
 
             @Override
             public VertexProperty.Cardinality getCardinality(final String key) {
-                return trait.getCardinality(key);
+                return VertexProperty.Cardinality.single;
             }
         }
 
@@ -472,6 +417,11 @@
             }
 
             @Override
+            public boolean supportsNullPropertyValues() {
+                return false;
+            }
+
+            @Override
             public boolean supportsUserSuppliedIds() {
                 return false;
             }
@@ -503,6 +453,11 @@
             }
 
             @Override
+            public boolean supportsNullPropertyValues() {
+                return false;
+            }
+
+            @Override
             public boolean supportsMapValues() {
                 return false;
             }
diff --git a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jVertex.java b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jVertex.java
index 2bcd363..98b1893 100644
--- a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jVertex.java
+++ b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jVertex.java
@@ -21,12 +21,14 @@
 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.Property;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
 import org.apache.tinkerpop.gremlin.structure.util.ElementHelper;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 import org.apache.tinkerpop.gremlin.structure.util.wrapped.WrappedVertex;
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
+import org.neo4j.tinkerpop.api.Neo4jDirection;
 import org.neo4j.tinkerpop.api.Neo4jNode;
 import org.neo4j.tinkerpop.api.Neo4jRelationship;
 
@@ -73,7 +75,18 @@
     @Override
     public void remove() {
         this.graph.tx().readWrite();
-        this.graph.trait.removeVertex(this);
+        try {
+            final Neo4jNode node = (Neo4jNode) baseElement;
+            for (final Neo4jRelationship relationship : node.relationships(Neo4jDirection.BOTH)) {
+                relationship.delete();
+            }
+            node.delete();
+        } catch (final IllegalStateException ignored) {
+            // this one happens if the vertex is still chilling in the tx
+        } catch (final RuntimeException ex) {
+            if (!Neo4jHelper.isNotFound(ex)) throw ex;
+            // this one happens if the vertex is committed
+        }
     }
 
     @Override
@@ -82,19 +95,37 @@
         if (ElementHelper.getIdValue(keyValues).isPresent())
             throw Vertex.Exceptions.userSuppliedIdsNotSupported();
         this.graph.tx().readWrite();
-        return this.graph.trait.setVertexProperty(this, cardinality, key, value, keyValues);
+
+        if (cardinality != VertexProperty.Cardinality.single)
+            throw VertexProperty.Exceptions.multiPropertiesNotSupported();
+
+        if (null == value) {
+            properties(key).forEachRemaining(VertexProperty::remove);
+            return VertexProperty.empty();
+        }
+
+        if (keyValues.length > 0)
+            throw VertexProperty.Exceptions.metaPropertiesNotSupported();
+        try {
+            this.baseElement.setProperty(key, value);
+            return new Neo4jVertexProperty<>(this, key, value);
+        } catch (final IllegalArgumentException iae) {
+            throw Property.Exceptions.dataTypeOfPropertyValueNotSupported(value, iae);
+        }
     }
 
     @Override
     public <V> VertexProperty<V> property(final String key) {
         this.graph.tx().readWrite();
-        return this.graph.trait.getVertexProperty(this, key);
+        return baseElement.hasProperty(key) ? new Neo4jVertexProperty<>(this, key, (V) baseElement.getProperty(key)) : VertexProperty.<V>empty();
     }
 
     @Override
     public <V> Iterator<VertexProperty<V>> properties(final String... propertyKeys) {
         this.graph.tx().readWrite();
-        return this.graph.trait.getVertexProperties(this, propertyKeys);
+        return (Iterator) IteratorUtils.stream(this.baseElement.getKeys())
+                .filter(key -> ElementHelper.keyExists(key, propertyKeys))
+                .map(key -> new Neo4jVertexProperty<>(this, key, (V) this.baseElement.getProperty(key))).iterator();
     }
 
     @Override
@@ -112,7 +143,7 @@
     public Iterator<Vertex> vertices(final Direction direction, final String... edgeLabels) {
         this.graph.tx().readWrite();
         return new Iterator<Vertex>() {
-            final Iterator<Neo4jRelationship> relationshipIterator = IteratorUtils.filter(0 == edgeLabels.length ?
+            final Iterator<Neo4jRelationship> relationshipIterator = 0 == edgeLabels.length ?
                     BOTH == direction ?
                             IteratorUtils.concat(getBaseVertex().relationships(Neo4jHelper.mapDirection(OUT)).iterator(),
                                     getBaseVertex().relationships(Neo4jHelper.mapDirection(IN)).iterator()) :
@@ -120,7 +151,7 @@
                     BOTH == direction ?
                             IteratorUtils.concat(getBaseVertex().relationships(Neo4jHelper.mapDirection(OUT), (edgeLabels)).iterator(),
                                     getBaseVertex().relationships(Neo4jHelper.mapDirection(IN), (edgeLabels)).iterator()) :
-                            getBaseVertex().relationships(Neo4jHelper.mapDirection(direction), (edgeLabels)).iterator(), graph.trait.getRelationshipPredicate());
+                            getBaseVertex().relationships(Neo4jHelper.mapDirection(direction), (edgeLabels)).iterator();
 
             @Override
             public boolean hasNext() {
@@ -138,7 +169,7 @@
     public Iterator<Edge> edges(final Direction direction, final String... edgeLabels) {
         this.graph.tx().readWrite();
         return new Iterator<Edge>() {
-            final Iterator<Neo4jRelationship> relationshipIterator = IteratorUtils.filter(0 == edgeLabels.length ?
+            final Iterator<Neo4jRelationship> relationshipIterator = 0 == edgeLabels.length ?
                     BOTH == direction ?
                             IteratorUtils.concat(getBaseVertex().relationships(Neo4jHelper.mapDirection(OUT)).iterator(),
                                     getBaseVertex().relationships(Neo4jHelper.mapDirection(IN)).iterator()) :
@@ -146,7 +177,7 @@
                     BOTH == direction ?
                             IteratorUtils.concat(getBaseVertex().relationships(Neo4jHelper.mapDirection(OUT), (edgeLabels)).iterator(),
                                     getBaseVertex().relationships(Neo4jHelper.mapDirection(IN), (edgeLabels)).iterator()) :
-                            getBaseVertex().relationships(Neo4jHelper.mapDirection(direction), (edgeLabels)).iterator(), graph.trait.getRelationshipPredicate());
+                            getBaseVertex().relationships(Neo4jHelper.mapDirection(direction), (edgeLabels)).iterator();
 
             @Override
             public boolean hasNext() {
diff --git a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jVertexProperty.java b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jVertexProperty.java
index 108aec2..b5fa2af 100644
--- a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jVertexProperty.java
+++ b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jVertexProperty.java
@@ -93,21 +93,19 @@
 
     @Override
     public <U> Iterator<Property<U>> properties(final String... propertyKeys) {
-        this.vertex.graph.tx().readWrite();
-        return this.vertex.graph.trait.getProperties(this, propertyKeys);
+        throw VertexProperty.Exceptions.metaPropertiesNotSupported();
     }
 
     @Override
     public <U> Property<U> property(final String key, final U value) {
-        this.vertex.graph.tx().readWrite();
-        ElementHelper.validateProperty(key, value);
-        return this.vertex.graph.trait.setProperty(this, key, value);
+        throw VertexProperty.Exceptions.metaPropertiesNotSupported();
     }
 
     @Override
     public void remove() {
         this.vertex.graph.tx().readWrite();
-        this.vertex.graph.trait.removeVertexProperty(this);
+        final Neo4jNode node = ((Neo4jVertex) element()).getBaseVertex();
+        if (node.hasProperty(key)) node.removeProperty(key);
         this.vertexPropertyNode= null;
     }
 
diff --git a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/trait/MultiMetaNeo4jTrait.java b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/trait/MultiMetaNeo4jTrait.java
deleted file mode 100644
index 5ded961..0000000
--- a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/trait/MultiMetaNeo4jTrait.java
+++ /dev/null
@@ -1,306 +0,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.
- */
-package org.apache.tinkerpop.gremlin.neo4j.structure.trait;
-
-import org.apache.tinkerpop.gremlin.neo4j.process.traversal.LabelP;
-import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph;
-import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jHelper;
-import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jProperty;
-import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jVertex;
-import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jVertexProperty;
-import org.apache.tinkerpop.gremlin.process.traversal.Compare;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer;
-import org.apache.tinkerpop.gremlin.structure.Element;
-import org.apache.tinkerpop.gremlin.structure.Graph;
-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.util.ElementHelper;
-import org.apache.tinkerpop.gremlin.structure.util.wrapped.WrappedGraph;
-import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
-import org.neo4j.tinkerpop.api.Neo4jDirection;
-import org.neo4j.tinkerpop.api.Neo4jGraphAPI;
-import org.neo4j.tinkerpop.api.Neo4jNode;
-import org.neo4j.tinkerpop.api.Neo4jRelationship;
-
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Optional;
-import java.util.function.Predicate;
-import java.util.stream.Stream;
-
-/**
- * @author Marko A. Rodriguez (http://markorodriguez.com)
- * @deprecated As of release 3.3.8, not replaced.
- */
-@Deprecated
-public final class MultiMetaNeo4jTrait implements Neo4jTrait {
-
-    private static final MultiMetaNeo4jTrait INSTANCE = new MultiMetaNeo4jTrait();
-
-    public static final String VERTEX_PROPERTY_LABEL = "vertexProperty";
-    public static final String VERTEX_PROPERTY_TOKEN = Graph.Hidden.hide("vertexProperty");
-
-    private static final Predicate<Neo4jNode> NODE_PREDICATE = node -> !node.hasLabel(VERTEX_PROPERTY_LABEL);
-    private static final Predicate<Neo4jRelationship> RELATIONSHIP_PREDICATE = relationship -> !Graph.Hidden.isHidden(relationship.type());
-
-    private MultiMetaNeo4jTrait() {
-
-    }
-
-    public static MultiMetaNeo4jTrait instance() {
-        return INSTANCE;
-    }
-
-    @Override
-    public Predicate<Neo4jNode> getNodePredicate() {
-        return NODE_PREDICATE;
-    }
-
-    @Override
-    public Predicate<Neo4jRelationship> getRelationshipPredicate() {
-        return RELATIONSHIP_PREDICATE;
-    }
-
-    @Override
-    public void removeVertex(final Neo4jVertex vertex) {
-        try {
-            final Neo4jNode node = vertex.getBaseVertex();
-            for (final Neo4jRelationship relationship : node.relationships(Neo4jDirection.BOTH)) {
-                final Neo4jNode otherNode = relationship.other(node);
-                if (otherNode.hasLabel(VERTEX_PROPERTY_LABEL)) {
-                    otherNode.delete(); // meta property node
-                }
-                relationship.delete();
-            }
-            node.delete();
-        } catch (final IllegalStateException ignored) {
-            // this one happens if the vertex is still chilling in the tx
-        } catch (final RuntimeException ex) {
-            if (!Neo4jHelper.isNotFound(ex)) throw ex;
-            // this one happens if the vertex is committed
-        }
-    }
-
-    @Override
-    public <V> VertexProperty<V> getVertexProperty(final Neo4jVertex vertex, final String key) {
-        final Neo4jNode node = vertex.getBaseVertex();
-        if (node.hasProperty(key)) {
-            if (node.getProperty(key).equals(VERTEX_PROPERTY_TOKEN)) {
-                if (node.degree(Neo4jDirection.OUTGOING, Graph.Hidden.hide(key)) > 1)
-                    throw Vertex.Exceptions.multiplePropertiesExistForProvidedKey(key);
-                else {
-                    return (VertexProperty<V>) new Neo4jVertexProperty<>(vertex, node.relationships(Neo4jDirection.OUTGOING, Graph.Hidden.hide(key)).iterator().next().end());
-                }
-            } else {
-                return new Neo4jVertexProperty<>(vertex, key, (V) node.getProperty(key));
-            }
-        } else
-            return VertexProperty.<V>empty();
-    }
-
-    @Override
-    public <V> Iterator<VertexProperty<V>> getVertexProperties(final Neo4jVertex vertex, final String... keys) {
-        if (Neo4jHelper.isDeleted(vertex.getBaseVertex()))
-            return Collections.emptyIterator(); // TODO: I believe its because the vertex property is deleted, but then seen again in the iterator. ?
-        return IteratorUtils.stream(vertex.getBaseVertex().getKeys())
-                .filter(key -> ElementHelper.keyExists(key, keys))
-                .flatMap(key -> {
-                    if (vertex.getBaseVertex().getProperty(key).equals(VERTEX_PROPERTY_TOKEN))
-                        return IteratorUtils.stream(vertex.getBaseVertex().relationships(Neo4jDirection.OUTGOING, Graph.Hidden.hide(key)))
-                                .map(relationship -> (VertexProperty<V>) new Neo4jVertexProperty<>(vertex, relationship.end()));
-                    else
-                        return Stream.of(new Neo4jVertexProperty<>(vertex, key, (V) vertex.getBaseVertex().getProperty(key)));
-                }).iterator();
-    }
-
-    @Override
-    public <V> VertexProperty<V> setVertexProperty(final Neo4jVertex vertex, final VertexProperty.Cardinality cardinality,
-                                                   final String key, final V value, final Object... keyValues) {
-        try {
-            final Optional<VertexProperty<V>> optionalVertexProperty = ElementHelper.stageVertexProperty(vertex, cardinality, key, value, keyValues);
-            if (optionalVertexProperty.isPresent()) return optionalVertexProperty.get();
-            final Neo4jNode node = vertex.getBaseVertex();
-            final Neo4jGraphAPI graph = ((Neo4jGraph) vertex.graph()).getBaseGraph();
-            final String prefixedKey = Graph.Hidden.hide(key);
-            if (node.hasProperty(key)) {
-                if (node.getProperty(key).equals(VERTEX_PROPERTY_TOKEN)) {
-                    final Neo4jNode vertexPropertyNode = graph.createNode(VERTEX_PROPERTY_LABEL, key);
-                    vertexPropertyNode.setProperty(T.key.getAccessor(), key);
-                    vertexPropertyNode.setProperty(T.value.getAccessor(), value);
-                    vertexPropertyNode.setProperty(key, value);
-                    node.connectTo(vertexPropertyNode, prefixedKey);
-                    final Neo4jVertexProperty<V> property = new Neo4jVertexProperty<>(vertex, key, value, vertexPropertyNode);
-                    ElementHelper.attachProperties(property, keyValues); // TODO: make this inlined
-                    return property;
-                } else {
-                    // move current key to be a vertex property node
-                    Neo4jNode vertexPropertyNode = graph.createNode(VERTEX_PROPERTY_LABEL, key);
-                    final Object tempValue = node.removeProperty(key);
-                    vertexPropertyNode.setProperty(T.key.getAccessor(), key);
-                    vertexPropertyNode.setProperty(T.value.getAccessor(), tempValue);
-                    vertexPropertyNode.setProperty(key, tempValue);
-                    node.connectTo(vertexPropertyNode, prefixedKey);
-                    node.setProperty(key, VERTEX_PROPERTY_TOKEN);
-                    vertexPropertyNode = graph.createNode(VERTEX_PROPERTY_LABEL, key);
-                    vertexPropertyNode.setProperty(T.key.getAccessor(), key);
-                    vertexPropertyNode.setProperty(T.value.getAccessor(), value);
-                    vertexPropertyNode.setProperty(key, value);
-                    node.connectTo(vertexPropertyNode, prefixedKey);
-                    final Neo4jVertexProperty<V> property = new Neo4jVertexProperty<>(vertex, key, value, vertexPropertyNode);
-                    ElementHelper.attachProperties(property, keyValues); // TODO: make this inlined
-                    return property;
-                }
-            } else {
-                node.setProperty(key, value);
-                final Neo4jVertexProperty<V> property = new Neo4jVertexProperty<>(vertex, key, value);
-                ElementHelper.attachProperties(property, keyValues); // TODO: make this inlined
-                return property;
-            }
-        } catch (final IllegalArgumentException iae) {
-            throw Property.Exceptions.dataTypeOfPropertyValueNotSupported(value, iae);
-        }
-    }
-
-    @Override
-    public VertexProperty.Cardinality getCardinality(final String key) {
-        return VertexProperty.Cardinality.list;
-    }
-
-    @Override
-    public boolean supportsMultiProperties() {
-        return true;
-    }
-
-    @Override
-    public boolean supportsMetaProperties() {
-        return true;
-    }
-
-    @Override
-    public void removeVertexProperty(final Neo4jVertexProperty vertexProperty) {
-        final Neo4jNode vertexPropertyNode = Neo4jHelper.getVertexPropertyNode(vertexProperty);
-        final Neo4jNode vertexNode = ((Neo4jVertex) vertexProperty.element()).getBaseVertex();
-        if (null == vertexPropertyNode) {
-            if (vertexNode.degree(Neo4jDirection.OUTGOING, Graph.Hidden.hide(vertexProperty.key())) == 0) {
-                if (vertexNode.hasProperty(vertexProperty.key()))
-                    vertexNode.removeProperty(vertexProperty.key());
-            }
-        } else {
-            vertexPropertyNode.relationships(Neo4jDirection.BOTH).forEach(Neo4jRelationship::delete);
-            vertexPropertyNode.delete();
-            if (vertexNode.degree(Neo4jDirection.OUTGOING, Graph.Hidden.hide(vertexProperty.key())) == 0) {
-                if (vertexNode.hasProperty(vertexProperty.key()))
-                    vertexNode.removeProperty(vertexProperty.key());
-            }
-        }
-    }
-
-    @Override
-    public <V> Property<V> setProperty(final Neo4jVertexProperty vertexProperty, final String key, final V value) {
-        final Neo4jNode vertexPropertyNode = Neo4jHelper.getVertexPropertyNode(vertexProperty);
-        if (null != vertexPropertyNode) {
-            vertexPropertyNode.setProperty(key, value);
-            return new Neo4jProperty<>(vertexProperty, key, value);
-        } else {
-            final Neo4jNode vertexNode = ((Neo4jVertex) vertexProperty.element()).getBaseVertex();
-            final Neo4jNode newVertexPropertyNode = ((WrappedGraph<Neo4jGraphAPI>) vertexProperty.element().graph()).getBaseGraph().createNode(VERTEX_PROPERTY_LABEL, vertexProperty.label());
-            newVertexPropertyNode.setProperty(T.key.getAccessor(), vertexProperty.key());
-            newVertexPropertyNode.setProperty(T.value.getAccessor(), vertexProperty.value());
-            newVertexPropertyNode.setProperty(vertexProperty.key(), vertexProperty.value());
-            newVertexPropertyNode.setProperty(key, value);
-            vertexNode.connectTo(newVertexPropertyNode, Graph.Hidden.hide(vertexProperty.key()));
-            vertexNode.setProperty(vertexProperty.key(), VERTEX_PROPERTY_TOKEN);
-            Neo4jHelper.setVertexPropertyNode(vertexProperty, newVertexPropertyNode);
-            return new Neo4jProperty<>(vertexProperty, key, value);
-        }
-    }
-
-    @Override
-    public <V> Property<V> getProperty(final Neo4jVertexProperty vertexProperty, final String key) {
-        final Neo4jNode vertexPropertyNode = Neo4jHelper.getVertexPropertyNode(vertexProperty);
-        if (null != vertexPropertyNode && vertexPropertyNode.hasProperty(key))
-            return new Neo4jProperty<>(vertexProperty, key, (V) vertexPropertyNode.getProperty(key));
-        else
-            return Property.empty();
-    }
-
-    @Override
-    public <V> Iterator<Property<V>> getProperties(final Neo4jVertexProperty vertexProperty, final String... keys) {
-        final Neo4jNode vertexPropertyNode = Neo4jHelper.getVertexPropertyNode(vertexProperty);
-        if (null == vertexPropertyNode)
-            return Collections.emptyIterator();
-        else
-            return IteratorUtils.stream(vertexPropertyNode.getKeys())
-                    .filter(key -> ElementHelper.keyExists(key, keys))
-                    .filter(key -> !key.equals(vertexProperty.key()))
-                    .map(key -> (Property<V>) new Neo4jProperty<>(vertexProperty, key, (V) vertexPropertyNode.getProperty(key))).iterator();
-
-    }
-
-    @Override
-    public Iterator<Vertex> lookupVertices(final Neo4jGraph graph, final List<HasContainer> hasContainers, final Object... ids) {
-        // ids are present, filter on them first
-        if (ids.length > 0)
-            return IteratorUtils.filter(graph.vertices(ids), vertex -> HasContainer.testAll(vertex, hasContainers));
-        ////// do index lookups //////
-        graph.tx().readWrite();
-        // get a label being search on
-        Optional<String> label = hasContainers.stream()
-                .filter(hasContainer -> hasContainer.getKey().equals(T.label.getAccessor()))
-                .filter(hasContainer -> Compare.eq == hasContainer.getBiPredicate())
-                .map(hasContainer -> (String) hasContainer.getValue())
-                .findAny();
-        if (!label.isPresent())
-            label = hasContainers.stream()
-                    .filter(hasContainer -> hasContainer.getKey().equals(T.label.getAccessor()))
-                    .filter(hasContainer -> hasContainer.getPredicate() instanceof LabelP)
-                    .map(hasContainer -> (String) hasContainer.getValue())
-                    .findAny();
-
-        if (label.isPresent()) {
-            // find a vertex by label and key/value
-            for (final HasContainer hasContainer : hasContainers) {
-                if (Compare.eq == hasContainer.getBiPredicate()) {
-                    if (graph.getBaseGraph().hasSchemaIndex(label.get(), hasContainer.getKey())) {
-                        return Stream.concat(
-                                IteratorUtils.stream(graph.getBaseGraph().findNodes(label.get(), hasContainer.getKey(), hasContainer.getValue()))
-                                        .filter(getNodePredicate())
-                                        .map(node -> (Vertex) new Neo4jVertex(node, graph))
-                                        .filter(vertex -> HasContainer.testAll(vertex, hasContainers)),
-                                IteratorUtils.stream(graph.getBaseGraph().findNodes(VERTEX_PROPERTY_LABEL, hasContainer.getKey(), hasContainer.getValue()))  // look up indexed vertex property nodes
-                                        .map(node -> node.relationships(Neo4jDirection.INCOMING).iterator().next().start())
-                                        .map(node -> (Vertex) new Neo4jVertex(node, graph))
-                                        .filter(vertex -> HasContainer.testAll(vertex, hasContainers))).iterator();
-                    }
-                }
-            }
-            // find a vertex by label
-            return IteratorUtils.stream(graph.getBaseGraph().findNodes(label.get()))
-                    .filter(getNodePredicate())
-                    .map(node -> (Vertex) new Neo4jVertex(node, graph))
-                    .filter(vertex -> HasContainer.testAll(vertex, hasContainers)).iterator();
-        } else {
-            // linear scan
-            return IteratorUtils.filter(graph.vertices(), vertex -> HasContainer.testAll(vertex, hasContainers));
-        }
-    }
-}
diff --git a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/trait/Neo4jTrait.java b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/trait/Neo4jTrait.java
deleted file mode 100644
index 085b3a4..0000000
--- a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/trait/Neo4jTrait.java
+++ /dev/null
@@ -1,74 +0,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.
- */
-package org.apache.tinkerpop.gremlin.neo4j.structure.trait;
-
-import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph;
-import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jVertex;
-import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jVertexProperty;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer;
-import org.apache.tinkerpop.gremlin.structure.Property;
-import org.apache.tinkerpop.gremlin.structure.Vertex;
-import org.apache.tinkerpop.gremlin.structure.VertexProperty;
-import org.neo4j.tinkerpop.api.Neo4jNode;
-import org.neo4j.tinkerpop.api.Neo4jRelationship;
-
-import java.util.Iterator;
-import java.util.List;
-import java.util.function.Predicate;
-
-/**
- * @author Marko A. Rodriguez (http://markorodriguez.com)
- * @deprecated As of release 3.3.8, not replaced.
- */
-@Deprecated
-public interface Neo4jTrait {
-
-    public Predicate<Neo4jNode> getNodePredicate();
-
-    public Predicate<Neo4jRelationship> getRelationshipPredicate();
-
-    public void removeVertex(final Neo4jVertex vertex);
-
-    public <V> VertexProperty<V> getVertexProperty(final Neo4jVertex vertex, final String key);
-
-    public <V> Iterator<VertexProperty<V>> getVertexProperties(final Neo4jVertex vertex, final String... keys);
-
-    public <V> VertexProperty<V> setVertexProperty(final Neo4jVertex vertex, final VertexProperty.Cardinality cardinality, final String key, final V value, final Object... keyValues);
-
-    ////
-
-    public boolean supportsMultiProperties();
-
-    public boolean supportsMetaProperties();
-
-    public VertexProperty.Cardinality getCardinality(final String key);
-
-    public void removeVertexProperty(final Neo4jVertexProperty vertexProperty);
-
-    public <V> Property<V> setProperty(final Neo4jVertexProperty vertexProperty, final String key, final V value);
-
-    public <V> Property<V> getProperty(final Neo4jVertexProperty vertexProperty, final String key);
-
-    public <V> Iterator<Property<V>> getProperties(final Neo4jVertexProperty vertexProperty, final String... keys);
-
-    ////
-
-    public Iterator<Vertex> lookupVertices(final Neo4jGraph graph, final List<HasContainer> hasContainers, final Object... ids);
-
-}
diff --git a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/trait/NoMultiNoMetaNeo4jTrait.java b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/trait/NoMultiNoMetaNeo4jTrait.java
deleted file mode 100644
index 119630f..0000000
--- a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/trait/NoMultiNoMetaNeo4jTrait.java
+++ /dev/null
@@ -1,191 +0,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.
- */
-package org.apache.tinkerpop.gremlin.neo4j.structure.trait;
-
-import org.apache.tinkerpop.gremlin.neo4j.process.traversal.LabelP;
-import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph;
-import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jHelper;
-import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jVertex;
-import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jVertexProperty;
-import org.apache.tinkerpop.gremlin.process.traversal.Compare;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer;
-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.util.ElementHelper;
-import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
-import org.neo4j.tinkerpop.api.Neo4jDirection;
-import org.neo4j.tinkerpop.api.Neo4jNode;
-import org.neo4j.tinkerpop.api.Neo4jRelationship;
-
-import java.util.Iterator;
-import java.util.List;
-import java.util.Optional;
-import java.util.function.Predicate;
-
-/**
- * @author Marko A. Rodriguez (http://markorodriguez.com)
- * @deprecated As of release 3.3.8, not replaced.
- */
-@Deprecated
-public final class NoMultiNoMetaNeo4jTrait implements Neo4jTrait {
-
-    private static final NoMultiNoMetaNeo4jTrait INSTANCE = new NoMultiNoMetaNeo4jTrait();
-
-    private final static Predicate TRUE_PREDICATE = x -> true;
-
-    public static NoMultiNoMetaNeo4jTrait instance() {
-        return INSTANCE;
-    }
-
-    private NoMultiNoMetaNeo4jTrait() {
-
-    }
-
-    @Override
-    public Predicate<Neo4jNode> getNodePredicate() {
-        return TRUE_PREDICATE;
-    }
-
-    @Override
-    public Predicate<Neo4jRelationship> getRelationshipPredicate() {
-        return TRUE_PREDICATE;
-    }
-
-    @Override
-    public void removeVertex(final Neo4jVertex vertex) {
-        try {
-            final Neo4jNode node = vertex.getBaseVertex();
-            for (final Neo4jRelationship relationship : node.relationships(Neo4jDirection.BOTH)) {
-                relationship.delete();
-            }
-            node.delete();
-        } catch (final IllegalStateException ignored) {
-            // this one happens if the vertex is still chilling in the tx
-        } catch (final RuntimeException ex) {
-            if (!Neo4jHelper.isNotFound(ex)) throw ex;
-            // this one happens if the vertex is committed
-        }
-    }
-
-    @Override
-    public <V> VertexProperty<V> getVertexProperty(final Neo4jVertex vertex, final String key) {
-        return vertex.getBaseVertex().hasProperty(key) ? new Neo4jVertexProperty<>(vertex, key, (V) vertex.getBaseVertex().getProperty(key)) : VertexProperty.<V>empty();
-    }
-
-    @Override
-    public <V> Iterator<VertexProperty<V>> getVertexProperties(final Neo4jVertex vertex, final String... keys) {
-        return (Iterator) IteratorUtils.stream(vertex.getBaseVertex().getKeys())
-                .filter(key -> ElementHelper.keyExists(key, keys))
-                .map(key -> new Neo4jVertexProperty<>(vertex, key, (V) vertex.getBaseVertex().getProperty(key))).iterator();
-    }
-
-    @Override
-    public <V> VertexProperty<V> setVertexProperty(final Neo4jVertex vertex, final VertexProperty.Cardinality cardinality, final String key, final V value, final Object... keyValues) {
-        if (cardinality != VertexProperty.Cardinality.single)
-            throw VertexProperty.Exceptions.multiPropertiesNotSupported();
-        if (keyValues.length > 0)
-            throw VertexProperty.Exceptions.metaPropertiesNotSupported();
-        try {
-            vertex.getBaseVertex().setProperty(key, value);
-            return new Neo4jVertexProperty<>(vertex, key, value);
-        } catch (final IllegalArgumentException iae) {
-            throw Property.Exceptions.dataTypeOfPropertyValueNotSupported(value, iae);
-        }
-    }
-
-    @Override
-    public VertexProperty.Cardinality getCardinality(final String key) {
-        return VertexProperty.Cardinality.single;
-    }
-
-    @Override
-    public boolean supportsMultiProperties() {
-        return false;
-    }
-
-    @Override
-    public boolean supportsMetaProperties() {
-        return false;
-    }
-
-    @Override
-    public void removeVertexProperty(final Neo4jVertexProperty vertexProperty) {
-        final Neo4jNode node = ((Neo4jVertex) vertexProperty.element()).getBaseVertex();
-        if (node.hasProperty(vertexProperty.key()))
-            node.removeProperty(vertexProperty.key());
-    }
-
-    @Override
-    public <V> Property<V> setProperty(final Neo4jVertexProperty vertexProperty, final String key, final V value) {
-        throw VertexProperty.Exceptions.metaPropertiesNotSupported();
-    }
-
-    @Override
-    public <V> Property<V> getProperty(final Neo4jVertexProperty vertexProperty, final String key) {
-        throw VertexProperty.Exceptions.metaPropertiesNotSupported();
-    }
-
-    @Override
-    public <V> Iterator<Property<V>> getProperties(final Neo4jVertexProperty vertexProperty, final String... keys) {
-        throw VertexProperty.Exceptions.metaPropertiesNotSupported();
-    }
-
-    @Override
-    public Iterator<Vertex> lookupVertices(final Neo4jGraph graph, final List<HasContainer> hasContainers, final Object... ids) {
-        // ids are present, filter on them first
-        if (ids.length > 0)
-            return IteratorUtils.filter(graph.vertices(ids), vertex -> HasContainer.testAll(vertex, hasContainers));
-        ////// do index lookups //////
-        graph.tx().readWrite();
-        // get a label being search on
-        Optional<String> label = hasContainers.stream()
-                .filter(hasContainer -> hasContainer.getKey().equals(T.label.getAccessor()))
-                .filter(hasContainer -> Compare.eq == hasContainer.getBiPredicate())
-                .map(hasContainer -> (String) hasContainer.getValue())
-                .findAny();
-        if (!label.isPresent())
-            label = hasContainers.stream()
-                    .filter(hasContainer -> hasContainer.getKey().equals(T.label.getAccessor()))
-                    .filter(hasContainer -> hasContainer.getPredicate() instanceof LabelP)
-                    .map(hasContainer -> (String) hasContainer.getValue())
-                    .findAny();
-
-        if (label.isPresent()) {
-            // find a vertex by label and key/value
-            for (final HasContainer hasContainer : hasContainers) {
-                if (Compare.eq == hasContainer.getBiPredicate() && !hasContainer.getKey().equals(T.label.getAccessor())) {
-                    if (graph.getBaseGraph().hasSchemaIndex(label.get(), hasContainer.getKey())) {
-                        return IteratorUtils.stream(graph.getBaseGraph().findNodes(label.get(), hasContainer.getKey(), hasContainer.getValue()))
-                                .map(node -> (Vertex) new Neo4jVertex(node, graph))
-                                .filter(vertex -> HasContainer.testAll(vertex, hasContainers)).iterator();
-                    }
-                }
-            }
-            // find a vertex by label
-            return IteratorUtils.stream(graph.getBaseGraph().findNodes(label.get()))
-                    .map(node -> (Vertex) new Neo4jVertex(node, graph))
-                    .filter(vertex -> HasContainer.testAll(vertex, hasContainers)).iterator();
-        } else {
-            // linear scan
-            return IteratorUtils.filter(graph.vertices(), vertex -> HasContainer.testAll(vertex, hasContainers));
-        }
-    }
-}
diff --git a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/AbstractNeo4jGraphProvider.java b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/AbstractNeo4jGraphProvider.java
index 98e1f5b..7ebd3ec 100644
--- a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/AbstractNeo4jGraphProvider.java
+++ b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/AbstractNeo4jGraphProvider.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.neo4j;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.AbstractGraphProvider;
 import org.apache.tinkerpop.gremlin.LoadGraphWith;
 import org.apache.tinkerpop.gremlin.TestHelper;
@@ -112,10 +112,6 @@
             graph.cypher("DROP INDEX ON :vertex(age)").iterate();
             graph.cypher("DROP INDEX ON :vertex(lang)").iterate();
             graph.tx().commit();
-        } else {
-            // TODO: add CREW work here.
-            // TODO: add meta_property indices when meta_property graph is provided
-            //throw new RuntimeException("Could not load graph with " + graphData);
         }
     }
 
@@ -160,10 +156,6 @@
                     graph.cypher("CREATE INDEX ON :vertex(lang)").iterate();
                 graph.tx().commit();
             } // else no indices
-        } else {
-            // TODO: add CREW work here.
-            // TODO: add meta_property indices when meta_property graph is provided
-            //throw new RuntimeException("Could not load graph with " + graphData);
         }
     }
 
diff --git a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/MultiMetaNeo4jGraphNativeNeo4jTest.java b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/MultiMetaNeo4jGraphNativeNeo4jTest.java
deleted file mode 100644
index f2caa9b..0000000
--- a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/MultiMetaNeo4jGraphNativeNeo4jTest.java
+++ /dev/null
@@ -1,33 +0,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.
- */
-package org.apache.tinkerpop.gremlin.neo4j;
-
-import org.apache.tinkerpop.gremlin.GraphProviderClass;
-import org.apache.tinkerpop.gremlin.neo4j.MultiMetaNeo4jGraphProvider;
-import org.apache.tinkerpop.gremlin.neo4j.NativeNeo4jSuite;
-import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph;
-import org.junit.runner.RunWith;
-
-/**
- * @author Marko A. Rodriguez (http://markorodriguez.com)
- */
-@RunWith(NativeNeo4jSuite.class)
-@GraphProviderClass(provider = MultiMetaNeo4jGraphProvider.class, graph = Neo4jGraph.class)
-public class MultiMetaNeo4jGraphNativeNeo4jTest {
-}
diff --git a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/MultiMetaNeo4jGraphProvider.java b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/MultiMetaNeo4jGraphProvider.java
deleted file mode 100644
index c7f082c..0000000
--- a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/MultiMetaNeo4jGraphProvider.java
+++ /dev/null
@@ -1,44 +0,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.
- */
-package org.apache.tinkerpop.gremlin.neo4j;
-
-import org.apache.tinkerpop.gremlin.LoadGraphWith;
-import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph;
-import org.apache.tinkerpop.gremlin.structure.Graph;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * @author Stephen Mallette (http://stephen.genoprime.com)
- */
-public class MultiMetaNeo4jGraphProvider extends AbstractNeo4jGraphProvider {
-    @Override
-    public Map<String, Object> getBaseConfiguration(final String graphName, final Class<?> test, final String testMethodName, final LoadGraphWith.GraphData graphData) {
-        final String directory = makeTestDirectory(graphName, test, testMethodName);
-
-        return new HashMap<String, Object>() {{
-            put(Graph.GRAPH, Neo4jGraph.class.getName());
-            put(Neo4jGraph.CONFIG_DIRECTORY, directory);
-            put(Neo4jGraph.CONFIG_META_PROPERTIES, true);
-            put(Neo4jGraph.CONFIG_MULTI_PROPERTIES, true);
-            put(Neo4jGraph.CONFIG_CONF + ".dbms.memory.pagecache.size", "1m");
-        }};
-    }
-}
diff --git a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/Neo4jGraphNativeNeo4jTest.java b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/Neo4jGraphNativeNeo4jTest.java
new file mode 100644
index 0000000..b212f78
--- /dev/null
+++ b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/Neo4jGraphNativeNeo4jTest.java
@@ -0,0 +1,31 @@
+/*
+ * 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.neo4j;
+
+import org.apache.tinkerpop.gremlin.GraphProviderClass;
+import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph;
+import org.junit.runner.RunWith;
+
+/**
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ */
+@RunWith(NativeNeo4jSuite.class)
+@GraphProviderClass(provider = Neo4jGraphProvider.class, graph = Neo4jGraph.class)
+public class Neo4jGraphNativeNeo4jTest {
+}
diff --git a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/Neo4jGraphProvider.java b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/Neo4jGraphProvider.java
new file mode 100644
index 0000000..c95d2d3
--- /dev/null
+++ b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/Neo4jGraphProvider.java
@@ -0,0 +1,42 @@
+/*
+ * 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.neo4j;
+
+import org.apache.tinkerpop.gremlin.LoadGraphWith;
+import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ */
+public class Neo4jGraphProvider extends AbstractNeo4jGraphProvider {
+    @Override
+    public Map<String, Object> getBaseConfiguration(final String graphName, final Class<?> test, final String testMethodName, final LoadGraphWith.GraphData graphData) {
+        final String directory = makeTestDirectory(graphName, test, testMethodName);
+
+        return new HashMap<String, Object>() {{
+            put(Graph.GRAPH, Neo4jGraph.class.getName());
+            put(Neo4jGraph.CONFIG_DIRECTORY, directory);
+            put(Neo4jGraph.CONFIG_CONF + ".dbms.memory.pagecache.size", "1m");
+        }};
+    }
+}
diff --git a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/NoMultiNoMetaNeo4jGraphNativeNeo4jTest.java b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/NoMultiNoMetaNeo4jGraphNativeNeo4jTest.java
deleted file mode 100644
index e186685..0000000
--- a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/NoMultiNoMetaNeo4jGraphNativeNeo4jTest.java
+++ /dev/null
@@ -1,33 +0,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.
- */
-package org.apache.tinkerpop.gremlin.neo4j;
-
-import org.apache.tinkerpop.gremlin.GraphProviderClass;
-import org.apache.tinkerpop.gremlin.neo4j.NativeNeo4jSuite;
-import org.apache.tinkerpop.gremlin.neo4j.NoMultiNoMetaNeo4jGraphProvider;
-import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph;
-import org.junit.runner.RunWith;
-
-/**
- * @author Marko A. Rodriguez (http://markorodriguez.com)
- */
-@RunWith(NativeNeo4jSuite.class)
-@GraphProviderClass(provider = NoMultiNoMetaNeo4jGraphProvider.class, graph = Neo4jGraph.class)
-public class NoMultiNoMetaNeo4jGraphNativeNeo4jTest {
-}
diff --git a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/NoMultiNoMetaNeo4jGraphProvider.java b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/NoMultiNoMetaNeo4jGraphProvider.java
deleted file mode 100644
index d0b015e..0000000
--- a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/NoMultiNoMetaNeo4jGraphProvider.java
+++ /dev/null
@@ -1,44 +0,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.
- */
-package org.apache.tinkerpop.gremlin.neo4j;
-
-import org.apache.tinkerpop.gremlin.LoadGraphWith;
-import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph;
-import org.apache.tinkerpop.gremlin.structure.Graph;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * @author Marko A. Rodriguez (http://markorodriguez.com)
- */
-public class NoMultiNoMetaNeo4jGraphProvider extends AbstractNeo4jGraphProvider {
-    @Override
-    public Map<String, Object> getBaseConfiguration(final String graphName, final Class<?> test, final String testMethodName, final LoadGraphWith.GraphData graphData) {
-        final String directory = makeTestDirectory(graphName, test, testMethodName);
-
-        return new HashMap<String, Object>() {{
-            put(Graph.GRAPH, Neo4jGraph.class.getName());
-            put(Neo4jGraph.CONFIG_DIRECTORY, directory);
-            put(Neo4jGraph.CONFIG_META_PROPERTIES, false);
-            put(Neo4jGraph.CONFIG_MULTI_PROPERTIES, false);
-            put(Neo4jGraph.CONFIG_CONF + ".dbms.memory.pagecache.size", "1m");
-        }};
-    }
-}
diff --git a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/process/MultiMetaNeo4jGraphProcessStandardTest.java b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/process/MultiMetaNeo4jGraphProcessStandardTest.java
deleted file mode 100644
index 62f7b83..0000000
--- a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/process/MultiMetaNeo4jGraphProcessStandardTest.java
+++ /dev/null
@@ -1,36 +0,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.
- */
-package org.apache.tinkerpop.gremlin.neo4j.process;
-
-import org.apache.tinkerpop.gremlin.GraphProviderClass;
-import org.apache.tinkerpop.gremlin.neo4j.MultiMetaNeo4jGraphProvider;
-import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph;
-import org.apache.tinkerpop.gremlin.process.ProcessStandardSuite;
-import org.junit.runner.RunWith;
-
-
-/**
- * Executes the Standard Gremlin Structure Test Suite using Neo4j.
- *
- * @author Stephen Mallette (http://stephen.genoprime.com)
- */
-@RunWith(ProcessStandardSuite.class)
-@GraphProviderClass(provider = MultiMetaNeo4jGraphProvider.class, graph = Neo4jGraph.class)
-public class MultiMetaNeo4jGraphProcessStandardTest {
-}
\ No newline at end of file
diff --git a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/process/Neo4jGraphProcessStandardTest.java b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/process/Neo4jGraphProcessStandardTest.java
new file mode 100644
index 0000000..3f2e819
--- /dev/null
+++ b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/process/Neo4jGraphProcessStandardTest.java
@@ -0,0 +1,33 @@
+/*
+ * 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.neo4j.process;
+
+import org.apache.tinkerpop.gremlin.GraphProviderClass;
+import org.apache.tinkerpop.gremlin.neo4j.Neo4jGraphProvider;
+import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph;
+import org.apache.tinkerpop.gremlin.process.ProcessStandardSuite;
+import org.junit.runner.RunWith;
+
+/**
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ */
+@RunWith(ProcessStandardSuite.class)
+@GraphProviderClass(provider = Neo4jGraphProvider.class, graph = Neo4jGraph.class)
+public class Neo4jGraphProcessStandardTest {
+}
diff --git a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/process/NoMultiNoMetaNeo4jGraphProcessStandardTest.java b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/process/NoMultiNoMetaNeo4jGraphProcessStandardTest.java
deleted file mode 100644
index b1b60be..0000000
--- a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/process/NoMultiNoMetaNeo4jGraphProcessStandardTest.java
+++ /dev/null
@@ -1,33 +0,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.
- */
-package org.apache.tinkerpop.gremlin.neo4j.process;
-
-import org.apache.tinkerpop.gremlin.GraphProviderClass;
-import org.apache.tinkerpop.gremlin.neo4j.NoMultiNoMetaNeo4jGraphProvider;
-import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph;
-import org.apache.tinkerpop.gremlin.process.ProcessStandardSuite;
-import org.junit.runner.RunWith;
-
-/**
- * @author Marko A. Rodriguez (http://markorodriguez.com)
- */
-@RunWith(ProcessStandardSuite.class)
-@GraphProviderClass(provider = NoMultiNoMetaNeo4jGraphProvider.class, graph = Neo4jGraph.class)
-public class NoMultiNoMetaNeo4jGraphProcessStandardTest {
-}
diff --git a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/structure/MultiMetaNeo4jGraphStructureStandardTest.java b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/structure/MultiMetaNeo4jGraphStructureStandardTest.java
deleted file mode 100644
index 0e56f28..0000000
--- a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/structure/MultiMetaNeo4jGraphStructureStandardTest.java
+++ /dev/null
@@ -1,35 +0,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.
- */
-package org.apache.tinkerpop.gremlin.neo4j.structure;
-
-import org.apache.tinkerpop.gremlin.GraphProviderClass;
-import org.apache.tinkerpop.gremlin.neo4j.MultiMetaNeo4jGraphProvider;
-import org.apache.tinkerpop.gremlin.structure.StructureStandardSuite;
-import org.junit.runner.RunWith;
-
-
-/**
- * Executes the Standard Gremlin Structure Test Suite using Neo4j.
- *
- * @author Stephen Mallette (http://stephen.genoprime.com)
- */
-@RunWith(StructureStandardSuite.class)
-@GraphProviderClass(provider = MultiMetaNeo4jGraphProvider.class, graph = Neo4jGraph.class)
-public class MultiMetaNeo4jGraphStructureStandardTest {
-}
diff --git a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/structure/NativeNeo4jIndexCheck.java b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/structure/NativeNeo4jIndexCheck.java
index 3591804..3f8f6bd 100644
--- a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/structure/NativeNeo4jIndexCheck.java
+++ b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/structure/NativeNeo4jIndexCheck.java
@@ -20,7 +20,6 @@
 
 import org.apache.tinkerpop.gremlin.FeatureRequirement;
 import org.apache.tinkerpop.gremlin.neo4j.AbstractNeo4jGremlinTest;
-import org.apache.tinkerpop.gremlin.neo4j.structure.trait.MultiMetaNeo4jTrait;
 import org.apache.tinkerpop.gremlin.process.traversal.P;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.structure.Graph;
@@ -83,47 +82,6 @@
     }
 
     @Test
-    @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_MULTI_PROPERTIES)
-    @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_META_PROPERTIES)
-    public void shouldHaveFasterRuntimeWithLabelKeyValueIndexOnMultiProperties() throws Exception {
-        final Neo4jGraph neo4j = (Neo4jGraph) this.graph;
-        int maxVertices = 10000;
-        for (int i = 0; i < maxVertices; i++) {
-            if (i % 2 == 0)
-                this.graph.addVertex(T.label, "something", "myId", i, "myId", i + maxVertices + 1);
-            else
-                this.graph.addVertex(T.label, "nothing", "myId", i, "myId", i + maxVertices + 1);
-        }
-        this.graph.tx().commit();
-
-        // traversal
-        final Runnable traversal = () -> {
-            final Traversal<Vertex, Vertex> t = g.V().hasLabel("something").has("myId", 2000 + maxVertices + 1);
-            final Vertex vertex = t.tryNext().get();
-            assertFalse(t.hasNext());
-            assertEquals(2, IteratorUtils.count(vertex.properties("myId")));
-            assertEquals("something", vertex.label());
-        };
-
-        // no index
-        this.graph.tx().readWrite();
-        assertFalse(this.getBaseGraph().hasSchemaIndex("something", "myId"));
-        TimeUtil.clock(20, traversal);
-        final double noIndexTime = TimeUtil.clock(20, traversal);
-        // index time
-        neo4j.cypher("CREATE INDEX ON :something(myId)").iterate();
-        neo4j.cypher("CREATE INDEX ON :vertexProperty(myId)").iterate();
-        this.graph.tx().commit();
-        this.graph.tx().readWrite();
-        Thread.sleep(5000); // wait for indices to be built
-        assertTrue(this.getBaseGraph().hasSchemaIndex("something", "myId"));
-        TimeUtil.clock(20, traversal);
-        final double indexTime = TimeUtil.clock(20, traversal);
-        logger.info("Query time (no-index vs. index): {}", noIndexTime + " vs. {}", indexTime);
-        assertTrue((noIndexTime / 10) > indexTime); // should be at least 10x faster
-    }
-
-    @Test
     public void shouldReturnResultsLabeledIndexOnVertexWithHasHas() {
         this.graph.tx().readWrite();
         this.getBaseGraph().execute("CREATE INDEX ON :Person(name)", null);
@@ -289,61 +247,6 @@
     }
 
     @Test
-    @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_MULTI_PROPERTIES)
-    public void shouldSupportVertexPropertyToVertexMappingOnIndexCalls() {
-        graph.tx().readWrite();
-        this.getBaseGraph().execute("CREATE INDEX ON :person(name)", null);
-//            this.graph.getBaseGraph().execute("CREATE INDEX ON :name(" + T.value.getAccessor() + ")", null);
-        this.graph.tx().commit();
-
-        final Vertex a = graph.addVertex(T.label, "person", "name", "marko", "age", 34);
-        a.property(VertexProperty.Cardinality.list, "name", "okram");
-        a.property(VertexProperty.Cardinality.list, "name", "marko a. rodriguez");
-        final Vertex b = graph.addVertex(T.label, "person", "name", "stephen");
-        final Vertex c = graph.addVertex("name", "matthias", "name", "mbroecheler");
-
-        tryCommit(graph, graph -> {
-            assertEquals(a.id(), g.V().has("person", "name", "okram").id().next());
-            assertEquals(1, g.V().has("person", "name", "okram").count().next().intValue());
-            assertEquals(34, ((Neo4jVertex) g.V().has("person", "name", "okram").next()).getBaseVertex().getProperty("age"));
-            assertEquals(MultiMetaNeo4jTrait.VERTEX_PROPERTY_TOKEN, ((Neo4jVertex) g.V().has("person", "name", "okram").next()).getBaseVertex().getProperty("name"));
-            ///
-            assertEquals(b.id(), g.V().has("person", "name", "stephen").id().next());
-            assertEquals(1, g.V().has("person", "name", "stephen").count().next().intValue());
-            assertEquals("stephen", ((Neo4jVertex) g.V().has("person", "name", "stephen").next()).getBaseVertex().getProperty("name"));
-            ///
-            assertEquals(c.id(), g.V().has("name", "matthias").id().next());
-            assertEquals(c.id(), g.V().has("name", "mbroecheler").id().next());
-            assertEquals(1, g.V().has("name", "matthias").count().next().intValue());
-            assertEquals(1, g.V().has("name", "mbroecheler").count().next().intValue());
-            assertEquals(0, g.V().has("person", "name", "matthias").count().next().intValue());
-            assertEquals(0, g.V().has("person", "name", "mbroecheler").count().next().intValue());
-        });
-
-        final Vertex d = graph.addVertex(T.label, "person", "name", "kuppitz");
-        tryCommit(graph, graph -> {
-            assertEquals(d.id(), g.V().has("person", "name", "kuppitz").id().next());
-            assertEquals("kuppitz", ((Neo4jVertex) g.V().has("person", "name", "kuppitz").next()).getBaseVertex().getProperty("name"));
-        });
-        d.property(VertexProperty.Cardinality.list, "name", "daniel", "acl", "private");
-        tryCommit(graph, graph -> {
-            assertEquals(d.id(), g.V().has("person", "name", P.within("daniel", "kuppitz")).id().next());
-            assertEquals(d.id(), g.V().has("person", "name", "kuppitz").id().next());
-            assertEquals(d.id(), g.V().has("person", "name", "daniel").id().next());
-            assertEquals(MultiMetaNeo4jTrait.VERTEX_PROPERTY_TOKEN, ((Neo4jVertex) g.V().has("person", "name", "kuppitz").next()).getBaseVertex().getProperty("name"));
-        });
-        d.property(VertexProperty.Cardinality.list, "name", "marko", "acl", "private");
-        tryCommit(graph, graph -> {
-            assertEquals(2, g.V().has("person", "name", "marko").count().next().intValue());
-            assertEquals(1, g.V().has("person", "name", "marko").properties("name").has(T.value, "marko").has("acl", "private").count().next().intValue());
-            g.V().has("person", "name", "marko").forEachRemaining(v -> {
-                assertEquals(MultiMetaNeo4jTrait.VERTEX_PROPERTY_TOKEN, ((Neo4jVertex) v).getBaseVertex().getProperty("name"));
-            });
-
-        });
-    }
-
-    @Test
     public void shouldDoLabelsNamespaceBehavior() {
         graph.tx().readWrite();
 
diff --git a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/structure/NativeNeo4jStructureCheck.java b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/structure/NativeNeo4jStructureCheck.java
index 8215ad3..2338a94 100644
--- a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/structure/NativeNeo4jStructureCheck.java
+++ b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/structure/NativeNeo4jStructureCheck.java
@@ -21,7 +21,6 @@
 import org.apache.tinkerpop.gremlin.FeatureRequirement;
 import org.apache.tinkerpop.gremlin.neo4j.AbstractNeo4jGremlinTest;
 import org.apache.tinkerpop.gremlin.neo4j.process.traversal.LabelP;
-import org.apache.tinkerpop.gremlin.neo4j.structure.trait.MultiMetaNeo4jTrait;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import org.apache.tinkerpop.gremlin.structure.Graph;
 import org.apache.tinkerpop.gremlin.structure.T;
@@ -153,9 +152,7 @@
     }
 
     @Test
-    @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_MULTI_PROPERTIES, supported = false)
-    @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_META_PROPERTIES, supported = false)
-    public void shouldNotGenerateNodesAndRelationshipsForNoMultiPropertiesNoMetaProperties() {
+    public void shouldNotGenerateNodesAndRelationships() {
         graph.tx().readWrite();
         tryCommit(graph, graph -> validateCounts(0, 0, 0, 0));
         Vertex vertex = graph.addVertex(T.label, "person");
@@ -183,201 +180,6 @@
     }
 
     @Test
-    @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_MULTI_PROPERTIES)
-    public void shouldGenerateNodesAndRelationshipsCorrectlyForVertexProperties() {
-
-        graph.tx().readWrite();
-        Neo4jVertex a = (Neo4jVertex) graph.addVertex("name", "marko", "name", "okram");
-        Neo4jVertex b = (Neo4jVertex) graph.addVertex("name", "stephen", "location", "virginia");
-
-        tryCommit(graph, graph -> {
-            assertEquals(2, g.V().count().next().intValue());
-            // assertEquals(2, a.properties("name").count().next().intValue());
-            // assertEquals(1, b.properties("name").count().next().intValue());
-            // assertEquals(1, b.properties("location").count().next().intValue());
-            assertEquals(0, g.E().count().next().intValue());
-
-            assertEquals(4l, this.getBaseGraph().execute("MATCH (n) RETURN COUNT(n)", null).next().get("COUNT(n)"));
-            assertEquals(2l, this.getBaseGraph().execute("MATCH (n)-[r]->(m) RETURN COUNT(r)", null).next().get("COUNT(r)"));
-            assertEquals(2l, this.getBaseGraph().execute("MATCH (a)-[r]->() WHERE id(a) = " + a.id() + " RETURN COUNT(r)", null).next().get("COUNT(r)"));
-            final AtomicInteger counter = new AtomicInteger(0);
-            a.getBaseVertex().relationships(Neo4jDirection.OUTGOING).forEach(relationship -> {
-                assertEquals(Graph.Hidden.hide("name"), relationship.type());
-                counter.incrementAndGet();
-            });
-            assertEquals(2, counter.getAndSet(0));
-            this.getBaseGraph().execute("MATCH (a)-->(m) WHERE id(a) = " + a.id() + " RETURN labels(m)", null).forEachRemaining(results -> {
-                assertEquals(true, ((List<String>) results.get("labels(m)")).contains(VertexProperty.DEFAULT_LABEL));
-                counter.incrementAndGet();
-            });
-            assertEquals(2, counter.getAndSet(0));
-            IteratorUtils.stream(a.getBaseVertex().relationships(Neo4jDirection.OUTGOING)).map(Neo4jRelationship::end).forEach(node -> {
-                assertEquals(3, IteratorUtils.count(node.getKeys()));  // T.key, T.value, key
-                assertEquals("name", node.getProperty(T.key.getAccessor()));
-                assertTrue("marko".equals(node.getProperty(T.value.getAccessor())) || "okram".equals(node.getProperty(T.value.getAccessor())));
-                assertEquals(0, node.degree(Neo4jDirection.OUTGOING, null));
-                assertEquals(1, node.degree(Neo4jDirection.INCOMING, null));
-                assertEquals(Graph.Hidden.hide("name"), node.relationships(Neo4jDirection.INCOMING).iterator().next().type());
-                counter.incrementAndGet();
-            });
-            assertEquals(2, counter.getAndSet(0));
-
-            assertEquals(2, IteratorUtils.count(b.getBaseVertex().getKeys()));
-            assertEquals("stephen", b.getBaseVertex().getProperty("name"));
-            assertEquals("virginia", b.getBaseVertex().getProperty("location"));
-        });
-
-        a.property("name", "the marko");
-        tryCommit(graph, graph -> {
-            assertEquals(2, g.V().count().next().intValue());
-            //assertEquals(1, a.prope rties().count().next().intValue());
-            //  assertEquals(1, b.properties("name").count().next().intValue());
-            // assertEquals(1, b.properties("location").count().next().intValue());
-            assertEquals(0, g.E().count().next().intValue());
-            assertEquals(2l, this.getBaseGraph().execute("MATCH (n) RETURN COUNT(n)", null).next().get("COUNT(n)"));
-            assertEquals(0l, this.getBaseGraph().execute("MATCH (n)-[r]->(m) RETURN COUNT(r)", null).next().get("COUNT(r)"));
-
-            assertEquals(1, IteratorUtils.count(a.getBaseVertex().getKeys()));
-            assertEquals("the marko", a.getBaseVertex().getProperty("name"));
-            assertEquals(2, IteratorUtils.count(b.getBaseVertex().getKeys()));
-            assertEquals("stephen", b.getBaseVertex().getProperty("name"));
-            assertEquals("virginia", b.getBaseVertex().getProperty("location"));
-        });
-
-        a.property("name").remove();
-        tryCommit(graph, graph -> {
-            assertEquals(2, g.V().count().next().intValue());
-            //    assertEquals(0, a.properties().count().next().intValue());
-            //   assertEquals(2, b.properties().count().next().intValue());
-            assertEquals(0, g.E().count().next().intValue());
-            assertEquals(2l, this.getBaseGraph().execute("MATCH (n) RETURN COUNT(n)", null).next().get("COUNT(n)"));
-            assertEquals(0l, this.getBaseGraph().execute("MATCH (n)-[r]->(m) RETURN COUNT(r)", null).next().get("COUNT(r)"));
-            assertEquals(0, IteratorUtils.count(a.getBaseVertex().getKeys()));
-            assertEquals(2, IteratorUtils.count(b.getBaseVertex().getKeys()));
-        });
-
-        graph.tx().commit();
-        a.property("name", "the marko", "acl", "private");
-        tryCommit(graph, graph -> {
-            assertEquals(2, g.V().count().next().intValue());
-            // assertEquals(1, a.properties("name").count().next().intValue());
-            // assertEquals(1, b.properties("name").count().next().intValue());
-            // assertEquals(1, b.properties("location").count().next().intValue());
-            assertEquals(0, g.E().count().next().intValue());
-
-            assertEquals(3l, this.getBaseGraph().execute("MATCH (n) RETURN COUNT(n)", null).next().get("COUNT(n)"));
-            assertEquals(1l, this.getBaseGraph().execute("MATCH (n)-[r]->(m) RETURN COUNT(r)", null).next().get("COUNT(r)"));
-            assertEquals(1l, this.getBaseGraph().execute("MATCH (a)-[r]->() WHERE id(a) = " + a.id() + " RETURN COUNT(r)", null).next().get("COUNT(r)"));
-            final AtomicInteger counter = new AtomicInteger(0);
-            a.getBaseVertex().relationships(Neo4jDirection.OUTGOING).forEach(relationship -> {
-                assertEquals(Graph.Hidden.hide("name"), relationship.type());
-                counter.incrementAndGet();
-            });
-            assertEquals(1, counter.getAndSet(0));
-            this.getBaseGraph().execute("MATCH (a)-->(m) WHERE id(a) = " + a.id() + " RETURN labels(m)", null).forEachRemaining(results -> {
-                assertEquals(true, ((List<String>) results.get("labels(m)")).contains(VertexProperty.DEFAULT_LABEL));
-                counter.incrementAndGet();
-            });
-            assertEquals(1, counter.getAndSet(0));
-            IteratorUtils.stream(a.getBaseVertex().relationships(Neo4jDirection.OUTGOING)).map(Neo4jRelationship::end).forEach(node -> {
-                assertEquals(4, IteratorUtils.count(node.getKeys()));
-                assertEquals("name", node.getProperty(T.key.getAccessor()));
-                assertEquals("the marko", node.getProperty(T.value.getAccessor()));
-                assertEquals("private", node.getProperty("acl"));
-                assertEquals(0, node.degree(Neo4jDirection.OUTGOING, null));
-                assertEquals(1, node.degree(Neo4jDirection.INCOMING, null));
-                assertEquals(Graph.Hidden.hide("name"), node.relationships(Neo4jDirection.INCOMING).iterator().next().type());
-                counter.incrementAndGet();
-            });
-            assertEquals(1, counter.getAndSet(0));
-
-            assertEquals(1, IteratorUtils.count(a.getBaseVertex().getKeys()));
-            assertTrue(a.getBaseVertex().hasProperty("name"));
-            assertEquals(MultiMetaNeo4jTrait.VERTEX_PROPERTY_TOKEN, a.getBaseVertex().getProperty("name"));
-            assertEquals(2, IteratorUtils.count(b.getBaseVertex().getKeys()));
-            assertEquals("stephen", b.getBaseVertex().getProperty("name"));
-            assertEquals("virginia", b.getBaseVertex().getProperty("location"));
-        });
-
-        a.property(VertexProperty.Cardinality.list, "name", "marko", "acl", "private");
-        a.property(VertexProperty.Cardinality.list, "name", "okram", "acl", "public");
-        a.property(VertexProperty.Cardinality.single, "name", "the marko", "acl", "private");
-        tryCommit(graph, graph -> {
-            assertEquals(2, g.V().count().next().intValue());
-            //assertEquals(1, a.properties("name").count().next().intValue());
-            //assertEquals(1, b.properties("name").count().next().intValue());
-            //assertEquals(1, b.properties("location").count().next().intValue());
-            assertEquals(0, g.E().count().next().intValue());
-
-            assertEquals(3l, this.getBaseGraph().execute("MATCH (n) RETURN COUNT(n)", null).next().get("COUNT(n)"));
-            assertEquals(1l, this.getBaseGraph().execute("MATCH (n)-[r]->(m) RETURN COUNT(r)", null).next().get("COUNT(r)"));
-            assertEquals(1l, this.getBaseGraph().execute("MATCH (a)-[r]->() WHERE id(a) = " + a.id() + " RETURN COUNT(r)", null).next().get("COUNT(r)"));
-            final AtomicInteger counter = new AtomicInteger(0);
-            a.getBaseVertex().relationships(Neo4jDirection.OUTGOING).forEach(relationship -> {
-                assertEquals(Graph.Hidden.hide("name"), relationship.type());
-                counter.incrementAndGet();
-            });
-            assertEquals(1, counter.getAndSet(0));
-            this.getBaseGraph().execute("MATCH (a)-->(m) WHERE id(a) = " + a.id() + " RETURN labels(m)", null).forEachRemaining(results -> {
-                assertEquals(true, ((List<String>) results.get("labels(m)")).contains(VertexProperty.DEFAULT_LABEL));
-                counter.incrementAndGet();
-            });
-            assertEquals(1, counter.getAndSet(0));
-            IteratorUtils.stream(a.getBaseVertex().relationships(Neo4jDirection.OUTGOING)).map(Neo4jRelationship::end).forEach(node -> {
-                assertEquals(4, IteratorUtils.count(node.getKeys()));
-                assertEquals("name", node.getProperty(T.key.getAccessor()));
-                assertEquals("the marko", node.getProperty(T.value.getAccessor()));
-                assertEquals("private", node.getProperty("acl"));
-                assertEquals(0, node.degree(Neo4jDirection.OUTGOING, null));
-                assertEquals(1, node.degree(Neo4jDirection.INCOMING, null));
-                assertEquals(Graph.Hidden.hide("name"), node.relationships(Neo4jDirection.INCOMING).iterator().next().type());
-                counter.incrementAndGet();
-            });
-            assertEquals(1, counter.getAndSet(0));
-
-            assertEquals(1, IteratorUtils.count(a.getBaseVertex().getKeys()));
-            assertTrue(a.getBaseVertex().hasProperty("name"));
-            assertEquals(MultiMetaNeo4jTrait.VERTEX_PROPERTY_TOKEN, a.getBaseVertex().getProperty("name"));
-            assertEquals(2, IteratorUtils.count(b.getBaseVertex().getKeys()));
-            assertEquals("stephen", b.getBaseVertex().getProperty("name"));
-            assertEquals("virginia", b.getBaseVertex().getProperty("location"));
-        });
-    }
-
-    @Test
-    @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_MULTI_PROPERTIES)
-    @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_META_PROPERTIES)
-    public void shouldNotGenerateNodesAndRelationshipsForMultiPropertiesWithSingle() {
-        graph.tx().readWrite();
-        tryCommit(graph, graph -> validateCounts(0, 0, 0, 0));
-        Vertex vertex = graph.addVertex(T.label, "person");
-        tryCommit(graph, graph -> validateCounts(1, 0, 1, 0));
-        vertex.property(VertexProperty.Cardinality.list, "name", "marko");
-        assertEquals("marko", vertex.value("name"));
-        tryCommit(graph, graph -> validateCounts(1, 0, 1, 0));
-        vertex.property(VertexProperty.Cardinality.single, "name", "okram");
-        tryCommit(graph, graph -> {
-            validateCounts(1, 0, 1, 0);
-            assertEquals("okram", vertex.value("name"));
-        });
-        VertexProperty vertexProperty = vertex.property("name");
-        tryCommit(graph, graph -> {
-            assertTrue(vertexProperty.isPresent());
-            assertEquals("name", vertexProperty.key());
-            assertEquals("okram", vertexProperty.value());
-            validateCounts(1, 0, 1, 0);
-        });
-
-        // now make it a meta property (and thus, force node/relationship creation)
-        vertexProperty.property("acl", "private");
-        tryCommit(graph, graph -> {
-            assertEquals("private", vertexProperty.value("acl"));
-            validateCounts(1, 0, 2, 1);
-        });
-
-    }
-
-    @Test
     public void shouldSupportNeo4jMultiLabels() {
         final Neo4jVertex vertex = (Neo4jVertex) graph.addVertex(T.label, "animal::person", "name", "marko");
         tryCommit(graph, graph -> {
diff --git a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jGraphStructureStandardTest.java b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jGraphStructureStandardTest.java
new file mode 100644
index 0000000..827b304
--- /dev/null
+++ b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jGraphStructureStandardTest.java
@@ -0,0 +1,32 @@
+/*
+ * 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.neo4j.structure;
+
+import org.apache.tinkerpop.gremlin.GraphProviderClass;
+import org.apache.tinkerpop.gremlin.neo4j.Neo4jGraphProvider;
+import org.apache.tinkerpop.gremlin.structure.StructureStandardSuite;
+import org.junit.runner.RunWith;
+
+/**
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ */
+@RunWith(StructureStandardSuite.class)
+@GraphProviderClass(provider = Neo4jGraphProvider.class, graph = Neo4jGraph.class)
+public class Neo4jGraphStructureStandardTest {
+}
diff --git a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/structure/NoMultiNoMetaNeo4jGraphStructureStandardTest.java b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/structure/NoMultiNoMetaNeo4jGraphStructureStandardTest.java
deleted file mode 100644
index 976744f..0000000
--- a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/structure/NoMultiNoMetaNeo4jGraphStructureStandardTest.java
+++ /dev/null
@@ -1,32 +0,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.
- */
-package org.apache.tinkerpop.gremlin.neo4j.structure;
-
-import org.apache.tinkerpop.gremlin.GraphProviderClass;
-import org.apache.tinkerpop.gremlin.neo4j.NoMultiNoMetaNeo4jGraphProvider;
-import org.apache.tinkerpop.gremlin.structure.StructureStandardSuite;
-import org.junit.runner.RunWith;
-
-/**
- * @author Marko A. Rodriguez (http://markorodriguez.com)
- */
-@RunWith(StructureStandardSuite.class)
-@GraphProviderClass(provider = NoMultiNoMetaNeo4jGraphProvider.class, graph = Neo4jGraph.class)
-public class NoMultiNoMetaNeo4jGraphStructureStandardTest {
-}
diff --git a/pom.xml b/pom.xml
index ed2a0cd..99f4a55 100644
--- a/pom.xml
+++ b/pom.xml
@@ -25,7 +25,7 @@
     </parent>
     <groupId>org.apache.tinkerpop</groupId>
     <artifactId>tinkerpop</artifactId>
-    <version>3.4.12-SNAPSHOT</version>
+    <version>3.5.1-SNAPSHOT</version>
     <packaging>pom</packaging>
     <name>Apache TinkerPop</name>
     <description>A Graph Computing Framework</description>
@@ -122,6 +122,7 @@
         </contributor>
     </contributors>
     <modules>
+        <module>gremlin-language</module>
         <module>gremlin-shaded</module>
         <module>gremlin-core</module>
         <module>gremlin-test</module>
@@ -146,25 +147,27 @@
         <url>https://github.com/apache/tinkerpop</url>
     </scm>
     <properties>
-        <commons.configuration.version>1.10</commons.configuration.version>
+        <commons.configuration.version>2.7</commons.configuration.version>
         <commons.lang.version>2.6</commons.lang.version>
         <commons.lang3.version>3.11</commons.lang3.version>
+        <commons.text.version>1.9</commons.text.version>
         <groovy.version>2.5.14</groovy.version>
-        <hadoop.version>2.7.2</hadoop.version>
+        <hadoop.version>2.7.7</hadoop.version>
         <java.tuples.version>1.2</java.tuples.version>
-        <javadoc-plugin.version>2.10.4</javadoc-plugin.version>
+        <javadoc-plugin.version>3.1.0</javadoc-plugin.version>
         <jcabi.version>1.1</jcabi.version>
         <log4j.version>1.2.17</log4j.version>
         <metrics.version>3.0.2</metrics.version>
         <netty.version>4.1.61.Final</netty.version>
         <slf4j.version>1.7.25</slf4j.version>
         <snakeyaml.version>1.27</snakeyaml.version>
-        <spark.version>2.4.0</spark.version>
-        <powermock.version>1.6.4</powermock.version>
+        <spark.version>3.0.0</spark.version>
+        <powermock.version>2.0.9</powermock.version>
 
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
         <skipIntegrationTests>true</skipIntegrationTests>
+        <suresafeArgs> </suresafeArgs>
 
         <!--
         This file will come from the root of each modules test/resources/ directories. log4j-silent.properties will
@@ -189,6 +192,7 @@
                 <artifactId>maven-compiler-plugin</artifactId>
             </plugin>
             <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-enforcer-plugin</artifactId>
                 <executions>
                     <execution>
@@ -200,7 +204,7 @@
                             <rules>
                                 <DependencyConvergence/>
                                 <requireJavaVersion>
-                                    <version>[1.8.0-40,)</version>
+                                    <version>[1.8,12)</version>
                                 </requireJavaVersion>
                                 <requireMavenVersion>
                                     <version>[3.3.9,)</version>
@@ -227,10 +231,10 @@
                                 <exclude>gremlin-javascript/src/main/javascript/gremlin-javascript/node_modules/**</exclude>
                                 <exclude>gremlin-javascript/src/main/javascript/gremlin-javascript/.idea/**</exclude>
                                 <exclude>gremlin-python/src/main/python-reports/**</exclude>
-                                <exclude>gremlin-python/src/main/python/**</exclude>
-                                <exclude>gremlin-python/src/main/jython/venv/**</exclude>
-                                <exclude>gremlin-python/src/main/jython/.pytest_cache/**</exclude>
-                                <exclude>gremlin-python/src/main/jython/.idea/**</exclude>
+                                <exclude>gremlin-python/src/main/jython/**</exclude>
+                                <exclude>gremlin-python/src/main/python/venv/**</exclude>
+                                <exclude>gremlin-python/src/main/python/.pytest_cache/**</exclude>
+                                <exclude>gremlin-python/src/main/python/.idea/**</exclude>
                             </excludes>
                         </configuration>
                     </execution>
@@ -244,7 +248,7 @@
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-javadoc-plugin</artifactId>
                 <configuration>
-                    <additionalparam>-Xdoclint:none</additionalparam>
+                    <additionalJOption>-Xdoclint:none</additionalJOption>
                     <tags>
                         <tag>
                             <name>example</name>
@@ -261,7 +265,7 @@
                         </goals>
                         <phase>site</phase>
                         <configuration>
-                            <additionalparam>-Xdoclint:none</additionalparam>
+                            <additionalJOption>-Xdoclint:none</additionalJOption>
                             <includeDependencySources>true</includeDependencySources>
                             <dependencySourceIncludes>
                                 <dependencySourceInclude>org.apache.tinkerpop:*</dependencySourceInclude>
@@ -366,6 +370,7 @@
                     <excludeSubProjects>false</excludeSubProjects>
                     <excludes>
                         <exclude>.mailmap</exclude>
+                        <exclude>.asf.yaml</exclude>
                         <exclude>.travis.yml</exclude>
                         <exclude>.travis.*.sh</exclude>
                         <exclude>.dockerignore</exclude>
@@ -388,6 +393,7 @@
                         <exclude>**/goal.txt</exclude>
                         <exclude>**/src/main/resources/META-INF/services/**</exclude>
                         <exclude>**/src/test/resources/META-INF/services/**</exclude>
+                        <exclude>**/src/test/resources/incorrect-traversals.txt</exclude>
                         <exclude>**/src/test/resources/org/apache/tinkerpop/gremlin/console/groovy/plugin/script-customizer-*.groovy</exclude>
                         <exclude>**/src/test/resources/org/apache/tinkerpop/gremlin/jsr223/script-customizer-*.groovy</exclude>
                         <exclude>**/src/test/resources/org/apache/tinkerpop/gremlin/console/jsr223/script-customizer-*.groovy</exclude>
@@ -414,10 +420,9 @@
                         <exclude>**/.vs/**</exclude>
                         <exclude>**/NuGet.Config</exclude>
                         <exclude>**/*.nuspec</exclude>
-                        <exclude>**/*.nuspec.template</exclude>
+                        <exclude>**/BenchmarkDotNet.Artifacts/**</exclude>
                         <exclude>**/gremlin-javascript/node_modules/**</exclude>
                         <exclude>**/gremlin-javascript/doc/**</exclude>
-                        <exclude>**/node/node_modules/**</exclude>
                         <exclude>**/node/**</exclude>
                         <exclude>**/npm-debug.log</exclude>
                         <exclude>**/_site/**</exclude>
@@ -457,10 +462,11 @@
         </plugins>
         <pluginManagement>
             <plugins>
+                <!-- there is a jdk11 profile that will be enabled if built with that version - these settings will be overriden -->
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-compiler-plugin</artifactId>
-                    <version>3.7.0</version>
+                    <version>3.8.1</version>
                     <configuration>
                         <source>1.8</source>
                         <target>1.8</target>
@@ -474,12 +480,17 @@
                     <artifactId>maven-deploy-plugin</artifactId>
                     <version>2.8.2</version>
                 </plugin>
+                <!-- reverted surefire to 2.21.0 for performance reasons. 2.22.2 required forkCount=1 and
+                     reuseForks=true which seemed to more the double the build time. there are only milestone
+                     releases after 2.22.2 so rather than rely on those at this time, i guess we just stick with
+                     2.21.0 -->
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-surefire-plugin</artifactId>
                     <version>2.21.0</version>
                     <configuration>
-                        <argLine>-Dlog4j.configuration=${log4j-test.properties} -Dbuild.dir=${project.build.directory} -Dis.testing=true -Djava.net.preferIPv4Stack=true
+                        <argLine>
+                            -Dlog4j.configuration=${log4j-test.properties} -Dbuild.dir=${project.build.directory} -Dis.testing=true -Djava.net.preferIPv4Stack=true ${suresafeArgs}
                         </argLine>
                         <trimStackTrace>false</trimStackTrace>
                         <excludes>
@@ -490,7 +501,7 @@
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-failsafe-plugin</artifactId>
-                    <version>2.21.0</version>
+                    <version>2.22.2</version>
                     <executions>
                         <execution>
                             <id>integration-test</id>
@@ -502,8 +513,11 @@
                                     <include>**/*IntegrateTest.java</include>
                                 </includes>
                                 <skipTests>${skipIntegrationTests}</skipTests>
-                                <argLine>-Dlog4j.configuration=${log4j-test.properties} -Dhost=localhost -Dport=8182 -Dbuild.dir=${project.build.directory} -Dis.testing=true -Djava.net.preferIPv4Stack=true
+                                <argLine>
+                                    -Dlog4j.configuration=${log4j-test.properties} -Dhost=localhost -Dport=8182 -Dbuild.dir=${project.build.directory} -Dis.testing=true -Djava.net.preferIPv4Stack=true ${suresafeArgs}
                                 </argLine>
+                                <forkCount>1</forkCount>
+                                <reuseForks>false</reuseForks>
                                 <summaryFile>target/failsafe-reports/failsafe-integration.xml</summaryFile>
                             </configuration>
                         </execution>
@@ -539,6 +553,9 @@
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-javadoc-plugin</artifactId>
                     <version>${javadoc-plugin.version}</version>
+                    <configuration>
+                        <source>1.8</source>
+                    </configuration>
                 </plugin>
                 <plugin>
                     <groupId>org.codehaus.gmavenplus</groupId>
@@ -551,7 +568,7 @@
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-shade-plugin</artifactId>
-                    <version>3.2.1</version>
+                    <version>3.2.4</version>
                 </plugin>
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
@@ -583,7 +600,7 @@
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-enforcer-plugin</artifactId>
-                    <version>1.4.1</version>
+                    <version>3.0.0-M3</version>
                 </plugin>
             </plugins>
         </pluginManagement>
@@ -591,20 +608,30 @@
 
     <dependencyManagement>
         <dependencies>
-            <!-- commons-configuration drags in the old commons-lang. need to update someday -->
             <dependency>
-                <groupId>commons-configuration</groupId>
-                <artifactId>commons-configuration</artifactId>
+                <groupId>org.apache.commons</groupId>
+                <artifactId>commons-configuration2</artifactId>
                 <version>${commons.configuration.version}</version>
                 <exclusions>
-                    <!-- self-conflict -->
+                    <!-- still on 1.8 and we need 1.9 -->
                     <exclusion>
-                        <groupId>commons-logging</groupId>
-                        <artifactId>commons-logging</artifactId>
+                        <groupId>org.apache.commons</groupId>
+                        <artifactId>commons-text</artifactId>
                     </exclusion>
                 </exclusions>
             </dependency>
             <dependency>
+                <groupId>org.apache.commons</groupId>
+                <artifactId>commons-text</artifactId>
+                <version>${commons.text.version}</version>
+            </dependency>
+            <!-- commons-configuration2 requires beanutils because we rely on file loaders -->
+            <dependency>
+                <groupId>commons-beanutils</groupId>
+                <artifactId>commons-beanutils</artifactId>
+                <version>1.9.4</version>
+            </dependency>
+            <dependency>
                 <groupId>commons-collections</groupId>
                 <artifactId>commons-collections</artifactId>
                 <version>3.2.2</version>
@@ -726,7 +753,7 @@
             <dependency>
                 <groupId>org.mockito</groupId>
                 <artifactId>mockito-core</artifactId>
-                <version>1.10.19</version>
+                <version>3.3.3</version>
                 <exclusions>
                     <exclusion>
                         <groupId>org.hamcrest</groupId>
@@ -735,21 +762,48 @@
                 </exclusions>
             </dependency>
             <dependency>
+                <groupId>org.objenesis</groupId>
+                <artifactId>objenesis</artifactId>
+                <version>2.4</version>
+            </dependency>
+            <dependency>
                 <groupId>org.powermock</groupId>
                 <artifactId>powermock-module-junit4</artifactId>
                 <version>${powermock.version}</version>
                 <scope>test</scope>
+                <exclusions>
+                    <!-- conflict with mockito - excluding from the mockito side doesn't work -->
+                    <exclusion>
+                        <groupId>net.bytebuddy</groupId>
+                        <artifactId>byte-buddy</artifactId>
+                    </exclusion>
+                    <exclusion>
+                        <groupId>net.bytebuddy</groupId>
+                        <artifactId>byte-buddy-agent</artifactId>
+                    </exclusion>
+                </exclusions>
             </dependency>
             <dependency>
                 <groupId>org.powermock</groupId>
-                <artifactId>powermock-api-mockito</artifactId>
+                <artifactId>powermock-api-mockito2</artifactId>
                 <version>${powermock.version}</version>
                 <scope>test</scope>
+                <exclusions>
+                    <!-- conflict with mockito - excluding from the mockito side doesn't work -->
+                    <exclusion>
+                        <groupId>net.bytebuddy</groupId>
+                        <artifactId>byte-buddy</artifactId>
+                    </exclusion>
+                    <exclusion>
+                        <groupId>net.bytebuddy</groupId>
+                        <artifactId>byte-buddy-agent</artifactId>
+                    </exclusion>
+                </exclusions>
             </dependency>
             <dependency>
                 <groupId>org.hamcrest</groupId>
-                <artifactId>hamcrest-all</artifactId>
-                <version>1.3</version>
+                <artifactId>hamcrest</artifactId>
+                <version>2.2</version>
             </dependency>
             <dependency>
                 <groupId>org.slf4j</groupId>
@@ -787,6 +841,33 @@
     <profiles>
 
         <profile>
+            <id>jdk11</id>
+            <activation>
+                <jdk>11</jdk>
+            </activation>
+            <properties>
+                <suresafeArgs>--illegal-access=permit</suresafeArgs>
+            </properties>
+            <build>
+                <pluginManagement>
+                    <plugins>
+                        <plugin>
+                            <groupId>org.apache.maven.plugins</groupId>
+                            <artifactId>maven-compiler-plugin</artifactId>
+                            <version>3.8.1</version>
+                            <configuration>
+                                <release>8</release>
+                                <compilerArgs>
+                                    <arg>-parameters</arg>
+                                </compilerArgs>
+                            </configuration>
+                        </plugin>
+                    </plugins>
+                </pluginManagement>
+            </build>
+        </profile>
+
+        <profile>
             <id>asciidoc</id>
             <activation>
                 <activeByDefault>false</activeByDefault>
@@ -1230,12 +1311,16 @@
                                 <inherited>false</inherited>
                                 <configuration>
                                     <destDir>full</destDir>
-                                    <additionalparam>-Xdoclint:none</additionalparam>
+                                    <additionalJOption>-Xdoclint:none</additionalJOption>
                                     <overview>${basedir}/docs/javadoc/overview.html</overview>
                                     <quiet>true</quiet>
                                     <sourcepath>
                                         gremlin-core/src/main/java:gremlin-driver/src/main/java:gremlin-groovy/src/main/java:gremlin-python/src/main/java:gremlin-server/src/main/java:gremlin-test/src/main/java:hadoop-gremlin/src/main/java:neo4j-gremlin/src/main/java:spark-gremlin/src/main/java:tinkergraph-gremlin/src/main/java
                                     </sourcepath>
+                                    <includeDependencySources>true</includeDependencySources>
+                                    <dependencySourceIncludes>
+                                        <dependencySourceInclude>org.apache.tinkerpop:*</dependencySourceInclude>
+                                    </dependencySourceIncludes>
                                 </configuration>
                             </execution>
                             <execution>
@@ -1247,7 +1332,7 @@
                                 <inherited>false</inherited>
                                 <configuration>
                                     <destDir>core</destDir>
-                                    <additionalparam>-Xdoclint:none</additionalparam>
+                                    <additionalJOption>-Xdoclint:none</additionalJOption>
                                     <overview>${basedir}/docs/javadoc/overview.html</overview>
                                     <quiet>true</quiet>
                                     <sourcepath>
@@ -1328,8 +1413,8 @@
                                          build for the "full" javadocs -->
                                     <additionalDependencies>
                                         <additionalDependency>
-                                            <groupId>commons-configuration</groupId>
-                                            <artifactId>commons-configuration</artifactId>
+                                            <groupId>org.apache.commons</groupId>
+                                            <artifactId>commons-configuration2</artifactId>
                                             <version>${commons.configuration.version}</version>
                                         </additionalDependency>
                                         <additionalDependency>
@@ -1453,7 +1538,7 @@
                         <groupId>org.apache.maven.plugins</groupId>
                         <artifactId>maven-surefire-plugin</artifactId>
                         <configuration>
-                            <argLine>-Dlog4j.configuration=${log4j-silent.properties} -Dbuild.dir=${project.build.directory} -Dis.testing=true -Djava.net.preferIPv4Stack=true
+                            <argLine>-Dlog4j.configuration=${log4j-silent.properties} -Dbuild.dir=${project.build.directory} -Dis.testing=true -Djava.net.preferIPv4Stack=true ${suresafeArgs}
                             </argLine>
                             <excludes>
                                 <exclude>**/*IntegrateTest.java</exclude>
@@ -1550,7 +1635,7 @@
                         <groupId>org.apache.maven.plugins</groupId>
                         <artifactId>maven-surefire-plugin</artifactId>
                         <configuration>
-                            <argLine>-Dlog4j.configuration=${log4j-test.properties} -Dbuild.dir=${project.build.directory} -Dis.testing=true ${surefireArgLine} -Djava.net.preferIPv4Stack=true
+                            <argLine>-Dlog4j.configuration=${log4j-test.properties} -Dbuild.dir=${project.build.directory} -Dis.testing=true ${suresafeArgs} -Djava.net.preferIPv4Stack=true
                             </argLine>
                         </configuration>
                     </plugin>
@@ -1558,7 +1643,7 @@
                         <groupId>org.apache.maven.plugins</groupId>
                         <artifactId>maven-failsafe-plugin</artifactId>
                         <configuration>
-                            <argLine>-Dlog4j.configuration=${log4j-test.properties} -Dhost=localhost -Dport=8182 -Dbuild.dir=${project.build.directory} -Dis.testing=true ${failsafeArgLine} -Djava.net.preferIPv4Stack=true
+                            <argLine>-Dlog4j.configuration=${log4j-test.properties} -Dhost=localhost -Dport=8182 -Dbuild.dir=${project.build.directory} -Dis.testing=true ${suresafeArgs} -Djava.net.preferIPv4Stack=true
                             </argLine>
                         </configuration>
                     </plugin>
@@ -1566,7 +1651,7 @@
                     <plugin>
                         <groupId>org.apache.maven.plugins</groupId>
                         <artifactId>maven-surefire-report-plugin</artifactId>
-                        <version>2.20</version>
+                        <version>2.22.2</version>
                         <executions>
                             <execution>
                                 <id>aggregate-surefire-report</id>
diff --git a/source-release.xml b/source-release.xml
index 370a1c7..bd599ce 100644
--- a/source-release.xml
+++ b/source-release.xml
@@ -88,11 +88,12 @@
                 <exclude>gremlin-dotnet/test/.glv</exclude>
                 <exclude>gremlin-python/.glv</exclude>
                 <exclude>gremlin-python/src/main/python-reports/**</exclude>
-                <exclude>gremlin-python/src/main/jython/venv/**</exclude>
-                <exclude>gremlin-python/src/main/jython/.pytest_cache/**</exclude>
-                <exclude>gremlin-python/src/main/jython/.idea/**</exclude>
-                <!-- on master/3.5.0 jython->python -->
-                <exclude>gremlin-python/src/main/python/**</exclude>
+                <exclude>gremlin-python/src/main/python/venv/**</exclude>
+                <exclude>gremlin-python/src/main/python/.pytest_cache/**</exclude>
+                <exclude>gremlin-python/src/main/python/.idea/**</exclude>
+                <exclude>gremlin-python/src/main/python/**/__pycache__/**</exclude>
+                <!-- on 3.4-dev/3.4.x python->jython -->
+                <exclude>gremlin-python/src/main/jython/**</exclude>
                 <exclude>gremlin-javascript/.glv</exclude>
                 <exclude>gremlin-javascript/src/main/javascript/gremlin-javascript/.idea/**</exclude>
                 <exclude>gremlin-javascript/src/main/javascript/gremlin-javascript/doc/**</exclude>
diff --git a/spark-gremlin/pom.xml b/spark-gremlin/pom.xml
index 4b0d63f..e6daba5 100644
--- a/spark-gremlin/pom.xml
+++ b/spark-gremlin/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.tinkerpop</groupId>
         <artifactId>tinkerpop</artifactId>
-        <version>3.4.12-SNAPSHOT</version>
+        <version>3.5.1-SNAPSHOT</version>
     </parent>
     <artifactId>spark-gremlin</artifactId>
     <name>Apache TinkerPop :: Spark Gremlin</name>
@@ -32,7 +32,7 @@
         <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
-            <version>14.0.1</version>
+            <version>16.0.1</version>
         </dependency>
         <dependency>
             <groupId>org.apache.tinkerpop</groupId>
@@ -44,257 +44,133 @@
             <artifactId>hadoop-gremlin</artifactId>
             <version>${project.version}</version>
             <exclusions>
-                <exclusion>
-                    <groupId>javax.servlet</groupId>
-                    <artifactId>servlet-api</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>javax.servlet</groupId>
-                    <artifactId>javax.servlet-api</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>com.sun.jersey</groupId>
-                    <artifactId>jersey-core</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>com.sun.jersey</groupId>
-                    <artifactId>jersey-server</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>commons-net</groupId>
-                    <artifactId>commons-net</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>commons-io</groupId>
-                    <artifactId>commons-io</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>com.google.guava</groupId>
-                    <artifactId>guava</artifactId>
-                </exclusion>
+                <!-- use our snappy as there is conflict within spark-->
                 <exclusion>
                     <groupId>org.xerial.snappy</groupId>
                     <artifactId>snappy-java</artifactId>
                 </exclusion>
+                <!-- use spark's avro -->
                 <exclusion>
                     <groupId>org.apache.avro</groupId>
                     <artifactId>avro</artifactId>
                 </exclusion>
+                <!-- use spark's math -->
                 <exclusion>
                     <groupId>org.apache.commons</groupId>
                     <artifactId>commons-math3</artifactId>
                 </exclusion>
-                <exclusion>
-                    <groupId>io.netty</groupId>
-                    <artifactId>netty</artifactId>
-                </exclusion>
+                <!-- use spark's netty 4-->
                 <exclusion>
                     <groupId>io.netty</groupId>
                     <artifactId>netty-all</artifactId>
                 </exclusion>
-                <exclusion>
-                    <groupId>com.thoughtworks.paranamer</groupId>
-                    <artifactId>paranamer</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-        <!-- SPARK -->
-        <dependency>
-            <groupId>org.apache.spark</groupId>
-            <artifactId>spark-core_2.11</artifactId>
-            <version>${spark.version}</version>
-            <exclusions>
-                <!-- self conflicts -->
-                <exclusion>
-                    <groupId>org.scala-lang</groupId>
-                    <artifactId>scala-compiler</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.apache.httpcomponents</groupId>
-                    <artifactId>httpclient</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.scala-lang.modules</groupId>
-                    <artifactId>scala-xml_2.11</artifactId>
-                </exclusion>
+                <!-- use spark's activation -->
                 <exclusion>
                     <groupId>javax.activation</groupId>
                     <artifactId>activation</artifactId>
                 </exclusion>
-                <exclusion>
-                    <groupId>org.codehaus.jackson</groupId>
-                    <artifactId>jackson-mapper-asl</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.codehaus.jackson</groupId>
-                    <artifactId>jackson-core-asl</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.scala-lang</groupId>
-                    <artifactId>scala-library</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>com.fasterxml.jackson.core</groupId>
-                    <artifactId>jackson-core</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>com.fasterxml.jackson.core</groupId>
-                    <artifactId>jackson-databind</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.scala-lang</groupId>
-                    <artifactId>scala-reflect</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.apache.httpcomponents</groupId>
-                    <artifactId>httpcore</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>javax.servlet</groupId>
-                    <artifactId>servlet-api</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>com.fasterxml.jackson.core</groupId>
-                    <artifactId>jackson-annotations</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>log4j</groupId>
-                    <artifactId>log4j</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.apache.commons</groupId>
-                    <artifactId>commons-lang3</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>commons-lang</groupId>
-                    <artifactId>commons-lang</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>commons-codec</groupId>
-                    <artifactId>commons-codec</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.xerial.snappy</groupId>
-                    <artifactId>snappy-java</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.apache.curator</groupId>
-                    <artifactId>curator-framework</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.apache.curator</groupId>
-                    <artifactId>curator-recipes</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>com.thoughtworks.paranamer</groupId>
-                    <artifactId>paranamer</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>javax.servlet</groupId>
-                    <artifactId>servlet-api</artifactId>
-                </exclusion>
-                <!-- gremlin-core conflicts -->
-                <exclusion>
-                    <groupId>org.slf4j</groupId>
-                    <artifactId>slf4j-api</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.slf4j</groupId>
-                    <artifactId>slf4j-log4j12</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.slf4j</groupId>
-                    <artifactId>jcl-over-slf4j</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.apache.ivy</groupId>
-                    <artifactId>ivy</artifactId>
-                </exclusion>
-                <!-- gremlin-groovy conflicts -->
-                <exclusion>
-                    <groupId>jline</groupId>
-                    <artifactId>jline</artifactId>
-                </exclusion>
-                <!-- hadoop conflicts -->
-                <exclusion>
-                    <groupId>org.apache.hadoop</groupId>
-                    <artifactId>hadoop-client</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.apache.curator</groupId>
-                    <artifactId>curator-client</artifactId>
-                </exclusion>
-                <!-- lgpl conflicts -->
-                <exclusion>
-                    <groupId>com.google.code.findbugs</groupId>
-                    <artifactId>jsr305</artifactId>
-                </exclusion>
+                <!-- use zookeeper's netty 3 -->
                 <exclusion>
                     <groupId>io.netty</groupId>
                     <artifactId>netty</artifactId>
                 </exclusion>
-                <exclusion>
-                    <groupId>io.netty</groupId>
-                    <artifactId>netty-all</artifactId>
-                </exclusion>
-                <!-- avro conflicts -->
+                <!-- use sparks commons-compress -->
                 <exclusion>
                     <groupId>org.apache.commons</groupId>
                     <artifactId>commons-compress</artifactId>
                 </exclusion>
             </exclusions>
         </dependency>
-        <!-- consistent dependencies -->
+        <!-- SPARK -->
         <dependency>
-            <groupId>org.scala-lang</groupId>
-            <artifactId>scala-library</artifactId>
-            <version>2.11.8</version>
-        </dependency>
-        <dependency>
-            <groupId>org.scala-lang.modules</groupId>
-            <artifactId>scala-xml_2.11</artifactId>
-            <version>1.0.5</version>
+            <groupId>org.apache.spark</groupId>
+            <artifactId>spark-core_2.12</artifactId>
+            <version>${spark.version}</version>
             <exclusions>
                 <exclusion>
+                    <groupId>org.apache.hadoop</groupId>
+                    <artifactId>hadoop-client</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>com.fasterxml.jackson.core</groupId>
+                    <artifactId>jackson-databind</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.zookeeper</groupId>
+                    <artifactId>zookeeper</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.xerial.snappy</groupId>
+                    <artifactId>snappy</artifactId>
+                </exclusion>
+                <exclusion>
                     <groupId>org.scala-lang</groupId>
                     <artifactId>scala-library</artifactId>
                 </exclusion>
+                <exclusion>
+                    <groupId>org.xerial.snappy</groupId>
+                    <artifactId>snappy-java</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>jakarta.annotation</groupId>
+                    <artifactId>jakarta.annotation-api</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.commons</groupId>
+                    <artifactId>commons-text</artifactId>
+                </exclusion>
+                <!--
+                spark 3.0/scala 2.12 uses paranamer 2.8 and hadoop is stuck with an older version. without 2.8 you get
+                SPARK-14220
+                -->
+                <exclusion>
+                    <groupId>com.thoughtworks.paranamer</groupId>
+                    <artifactId>paranamer</artifactId>
+                </exclusion>
             </exclusions>
         </dependency>
-        <dependency>
-            <groupId>com.fasterxml.jackson.core</groupId>
-            <artifactId>jackson-databind</artifactId>
-            <version>2.6.7</version>
-        </dependency>
-        <dependency>
-            <groupId>commons-lang</groupId>
-            <artifactId>commons-lang</artifactId>
-            <version>${commons.lang.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>com.thoughtworks.paranamer</groupId>
-            <artifactId>paranamer</artifactId>
-            <version>2.6</version>
-        </dependency>
+        <!-- spark self-conflict and hadoop conflict -->
         <dependency>
             <groupId>org.xerial.snappy</groupId>
             <artifactId>snappy-java</artifactId>
-            <version>1.1.1.7</version>
+            <version>1.1.7.3</version>
         </dependency>
+        <!-- spark self-conflict and hadoop conflict -->
         <dependency>
-            <groupId>io.netty</groupId>
-            <artifactId>netty-all</artifactId>
-            <version>4.1.32.Final</version>
+            <groupId>com.thoughtworks.paranamer</groupId>
+            <artifactId>paranamer</artifactId>
+            <version>2.8</version>
         </dependency>
+        <!-- spark self-conflict -->
         <dependency>
-            <groupId>io.netty</groupId>
-            <artifactId>netty</artifactId>
-            <version>3.9.9.Final</version>
+            <groupId>jakarta.annotation</groupId>
+            <artifactId>jakarta.annotation-api</artifactId>
+            <version>1.3.5</version>
         </dependency>
+        <!-- spark self-conflict -->
         <dependency>
-            <groupId>org.apache.commons</groupId>
-            <artifactId>commons-compress</artifactId>
-            <version>1.19</version>
+            <groupId>org.scala-lang</groupId>
+            <artifactId>scala-library</artifactId>
+            <version>2.12.10</version>
+        </dependency>
+        <!-- spark self-confict -->
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <version>2.10.0</version>
+        </dependency>
+        <!-- spark self-confict -->
+        <dependency>
+            <groupId>org.apache.zookeeper</groupId>
+            <artifactId>zookeeper</artifactId>
+            <version>3.4.6</version>
+            <exclusions>
+                <!-- use gremlin-groovy's jline -->
+                <exclusion>
+                    <groupId>jline</groupId>
+                    <artifactId>jline</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
         <!-- TEST -->
         <dependency>
@@ -302,16 +178,6 @@
             <artifactId>gremlin-test</artifactId>
             <version>${project.version}</version>
             <scope>test</scope>
-            <exclusions>
-                <exclusion>
-                    <groupId>com.google.guava</groupId>
-                    <artifactId>guava</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.objenesis</groupId>
-                    <artifactId>objenesis</artifactId>
-                </exclusion>
-            </exclusions>
         </dependency>
         <dependency>
             <groupId>org.apache.tinkerpop</groupId>
@@ -393,7 +259,7 @@
                     <archive>
                         <manifestEntries>
                             <Gremlin-Plugin-Dependencies>
-                                org.apache.hadoop:hadoop-client:${hadoop.version};org.apache.hadoop:hadoop-yarn-server-web-proxy:${hadoop.version};org.apache.spark:spark-yarn_2.11:${spark.version}
+                                org.apache.hadoop:hadoop-client:${hadoop.version};org.apache.hadoop:hadoop-yarn-server-web-proxy:${hadoop.version};org.apache.spark:spark-yarn_2.12:${spark.version}
                             </Gremlin-Plugin-Dependencies>
                             <!-- deletes the servlet-api jar from the path after install - causes conflicts -->
                             <Gremlin-Plugin-Paths>servlet-api-2.5.jar=</Gremlin-Plugin-Paths>
diff --git a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/process/computer/MemoryAccumulator.java b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/process/computer/MemoryAccumulator.java
index cf8cb25..fa72eb0 100644
--- a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/process/computer/MemoryAccumulator.java
+++ b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/process/computer/MemoryAccumulator.java
@@ -19,37 +19,58 @@
 
 package org.apache.tinkerpop.gremlin.spark.process.computer;
 
-import org.apache.spark.AccumulatorParam;
+import org.apache.spark.util.AccumulatorV2;
 import org.apache.tinkerpop.gremlin.hadoop.structure.io.ObjectWritable;
 import org.apache.tinkerpop.gremlin.process.computer.MemoryComputeKey;
 
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
+ * @author Stephen Mallette (http://stephen.genoprime.com)
  */
-public final class MemoryAccumulator<A> implements AccumulatorParam<ObjectWritable<A>> {
+public final class MemoryAccumulator<A> extends AccumulatorV2<ObjectWritable<A>, ObjectWritable<A>> {
 
     private final MemoryComputeKey<A> memoryComputeKey;
+    private ObjectWritable<A> value;
 
-    public MemoryAccumulator(final MemoryComputeKey<A> memoryComputeKey) {
+    MemoryAccumulator(final MemoryComputeKey<A> memoryComputeKey) {
+        this(memoryComputeKey, ObjectWritable.empty());
+    }
+
+    private MemoryAccumulator(final MemoryComputeKey<A> memoryComputeKey, final ObjectWritable<A> initial) {
         this.memoryComputeKey = memoryComputeKey;
+        this.value = initial;
     }
 
     @Override
-    public ObjectWritable<A> addAccumulator(final ObjectWritable<A> a, final ObjectWritable<A> b) {
-        if (a.isEmpty())
-            return b;
-        if (b.isEmpty())
-            return a;
-        return new ObjectWritable<>(this.memoryComputeKey.getReducer().apply(a.get(), b.get()));
+    public boolean isZero() {
+        return ObjectWritable.empty().equals(value);
     }
 
     @Override
-    public ObjectWritable<A> addInPlace(final ObjectWritable<A> a, final ObjectWritable<A> b) {
-        return this.addAccumulator(a, b);
+    public AccumulatorV2<ObjectWritable<A>, ObjectWritable<A>> copy() {
+        return new MemoryAccumulator<>(this.memoryComputeKey, this.value);
     }
 
     @Override
-    public ObjectWritable<A> zero(final ObjectWritable<A> a) {
-        return ObjectWritable.empty();
+    public void reset() {
+        this.value = ObjectWritable.empty();
+    }
+
+    @Override
+    public void add(final ObjectWritable<A> v) {
+        if (this.value.isEmpty())
+            this.value = v;
+        else if (!v.isEmpty())
+            this.value = new ObjectWritable<>(this.memoryComputeKey.getReducer().apply(value.get(), v.get()));
+    }
+
+    @Override
+    public void merge(final AccumulatorV2<ObjectWritable<A>, ObjectWritable<A>> other) {
+        this.add(other.value());
+    }
+
+    @Override
+    public ObjectWritable<A> value() {
+        return this.value;
     }
 }
diff --git a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/process/computer/SparkExecutor.java b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/process/computer/SparkExecutor.java
index e9372d0..59b8c22 100644
--- a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/process/computer/SparkExecutor.java
+++ b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/process/computer/SparkExecutor.java
@@ -19,7 +19,7 @@
 package org.apache.tinkerpop.gremlin.spark.process.computer;
 
 import org.apache.spark.api.java.Optional;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.spark.api.java.JavaPairRDD;
 import org.apache.spark.api.java.function.Function2;
 import org.apache.spark.api.java.function.PairFlatMapFunction;
diff --git a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/process/computer/SparkGraphComputer.java b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/process/computer/SparkGraphComputer.java
index 5184db6..d364b3d 100644
--- a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/process/computer/SparkGraphComputer.java
+++ b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/process/computer/SparkGraphComputer.java
@@ -18,9 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.spark.process.computer;
 
-import org.apache.commons.configuration.ConfigurationUtils;
-import org.apache.commons.configuration.FileConfiguration;
-import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.commons.configuration2.ConfigurationUtils;
+import org.apache.commons.configuration2.builder.fluent.Configurations;
 import org.apache.commons.lang3.concurrent.BasicThreadFactory;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.FileSystem;
@@ -102,7 +101,7 @@
  */
 public final class SparkGraphComputer extends AbstractHadoopGraphComputer {
 
-    private final org.apache.commons.configuration.Configuration sparkConfiguration;
+    private final org.apache.commons.configuration2.Configuration sparkConfiguration;
     private boolean workersSet = false;
     private final ThreadFactory threadFactoryBoss = new BasicThreadFactory.Builder().namingPattern(SparkGraphComputer.class.getSimpleName() + "-boss").build();
 
@@ -251,7 +250,7 @@
             //////////////////////////////////////////////////
             //////////////////////////////////////////////////
             // apache and hadoop configurations that are used throughout the graph computer computation
-            final org.apache.commons.configuration.Configuration graphComputerConfiguration = new HadoopConfiguration(this.sparkConfiguration);
+            final org.apache.commons.configuration2.Configuration graphComputerConfiguration = new HadoopConfiguration(this.sparkConfiguration);
             if (!graphComputerConfiguration.containsKey(Constants.SPARK_SERIALIZER)) {
                 graphComputerConfiguration.setProperty(Constants.SPARK_SERIALIZER, KryoSerializer.class.getCanonicalName());
                 if (!graphComputerConfiguration.containsKey(Constants.SPARK_KRYO_REGISTRATOR))
@@ -541,7 +540,8 @@
     }
 
     public static void main(final String[] args) throws Exception {
-        final FileConfiguration configuration = new PropertiesConfiguration(args[0]);
+        final Configurations configs = new Configurations();
+        final org.apache.commons.configuration2.Configuration configuration = configs.properties(args[0]);
         new SparkGraphComputer(HadoopGraph.open(configuration)).program(VertexProgram.createVertexProgram(HadoopGraph.open(configuration), configuration)).submit().get();
     }
 }
diff --git a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/process/computer/SparkMemory.java b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/process/computer/SparkMemory.java
index bf8590e..5a04162 100644
--- a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/process/computer/SparkMemory.java
+++ b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/process/computer/SparkMemory.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.spark.process.computer;
 
-import org.apache.spark.Accumulator;
+import org.apache.spark.util.AccumulatorV2;
 import org.apache.spark.api.java.JavaSparkContext;
 import org.apache.spark.broadcast.Broadcast;
 import org.apache.tinkerpop.gremlin.hadoop.structure.io.ObjectWritable;
@@ -46,7 +46,7 @@
 public final class SparkMemory implements Memory.Admin, Serializable {
 
     public final Map<String, MemoryComputeKey> memoryComputeKeys = new HashMap<>();
-    private final Map<String, Accumulator<ObjectWritable>> sparkMemory = new HashMap<>();
+    private final Map<String, AccumulatorV2<ObjectWritable,ObjectWritable>> sparkMemory = new HashMap<>();
     private final AtomicInteger iteration = new AtomicInteger(0);
     private final AtomicLong runtime = new AtomicLong(0l);
     private Broadcast<Map<String, Object>> broadcast;
@@ -62,9 +62,9 @@
             this.memoryComputeKeys.put(mapReduce.getMemoryKey(), MemoryComputeKey.of(mapReduce.getMemoryKey(), Operator.assign, false, false));
         }
         for (final MemoryComputeKey memoryComputeKey : this.memoryComputeKeys.values()) {
-            this.sparkMemory.put(
-                    memoryComputeKey.getKey(),
-                    sparkContext.accumulator(ObjectWritable.empty(), memoryComputeKey.getKey(), new MemoryAccumulator<>(memoryComputeKey)));
+            final AccumulatorV2<ObjectWritable, ObjectWritable> accumulator = new MemoryAccumulator<>(memoryComputeKey);
+            JavaSparkContext.toSparkContext(sparkContext).register(accumulator, memoryComputeKey.getKey());
+            this.sparkMemory.put(memoryComputeKey.getKey(), accumulator);
         }
         this.broadcast = sparkContext.broadcast(Collections.emptyMap());
     }
@@ -135,8 +135,10 @@
         checkKeyValue(key, value);
         if (this.inExecute)
             throw Memory.Exceptions.memorySetOnlyDuringVertexProgramSetUpAndTerminate(key);
-        else
-            this.sparkMemory.get(key).setValue(new ObjectWritable<>(value));
+        else {
+            this.sparkMemory.get(key).reset();
+            this.sparkMemory.get(key).add(new ObjectWritable<>(value));
+        }
     }
 
     @Override
diff --git a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/process/computer/traversal/strategy/optimization/interceptor/SparkStarBarrierInterceptor.java b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/process/computer/traversal/strategy/optimization/interceptor/SparkStarBarrierInterceptor.java
index de42525..7eb12d4 100644
--- a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/process/computer/traversal/strategy/optimization/interceptor/SparkStarBarrierInterceptor.java
+++ b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/process/computer/traversal/strategy/optimization/interceptor/SparkStarBarrierInterceptor.java
@@ -163,7 +163,7 @@
         final Step<?, ?> startStep = traversal.getStartStep();
         final Step<?, ?> endStep = traversal.getEndStep();
         // right now this is not supported because of how the SparkStarBarrierInterceptor mutates the traversal prior to local evaluation
-        if (traversal.getStrategies().toList().stream().filter(strategy -> strategy instanceof SubgraphStrategy).findAny().isPresent())
+        if (traversal.getStrategies().getStrategy(SubgraphStrategy.class).isPresent())
             return false;
         if (!startStep.getClass().equals(GraphStep.class) || ((GraphStep) startStep).returnsEdge())
             return false;
diff --git a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/Spark.java b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/Spark.java
index d9bfd68..697e649 100644
--- a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/Spark.java
+++ b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/Spark.java
@@ -19,7 +19,7 @@
 
 package org.apache.tinkerpop.gremlin.spark.structure;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.spark.SparkConf;
 import org.apache.spark.SparkContext;
 import org.apache.spark.rdd.RDD;
diff --git a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/InputFormatRDD.java b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/InputFormatRDD.java
index 9589497..eced132 100644
--- a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/InputFormatRDD.java
+++ b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/InputFormatRDD.java
@@ -19,7 +19,7 @@
 
 package org.apache.tinkerpop.gremlin.spark.structure.io;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.hadoop.io.NullWritable;
 import org.apache.hadoop.mapreduce.InputFormat;
 import org.apache.hadoop.mapreduce.lib.input.SequenceFileInputFormat;
diff --git a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/InputOutputHelper.java b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/InputOutputHelper.java
index 444b10a..f0a0453 100644
--- a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/InputOutputHelper.java
+++ b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/InputOutputHelper.java
@@ -19,8 +19,8 @@
 
 package org.apache.tinkerpop.gremlin.spark.structure.io;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.hadoop.Constants;
 import org.apache.tinkerpop.gremlin.hadoop.structure.HadoopConfiguration;
 import org.apache.tinkerpop.gremlin.hadoop.structure.HadoopGraph;
diff --git a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/InputRDD.java b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/InputRDD.java
index a1f044c..b37672e 100644
--- a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/InputRDD.java
+++ b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/InputRDD.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.spark.structure.io;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.hadoop.mapred.InputFormat;
 import org.apache.spark.api.java.JavaPairRDD;
 import org.apache.spark.api.java.JavaSparkContext;
diff --git a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/OutputFormatRDD.java b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/OutputFormatRDD.java
index fe848a0..3d169e4 100644
--- a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/OutputFormatRDD.java
+++ b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/OutputFormatRDD.java
@@ -19,7 +19,7 @@
 
 package org.apache.tinkerpop.gremlin.spark.structure.io;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.io.NullWritable;
 import org.apache.hadoop.mapreduce.OutputFormat;
diff --git a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/OutputRDD.java b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/OutputRDD.java
index 3332b4d..666534f 100644
--- a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/OutputRDD.java
+++ b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/OutputRDD.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.spark.structure.io;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.spark.api.java.JavaPairRDD;
 import org.apache.tinkerpop.gremlin.hadoop.Constants;
 import org.apache.tinkerpop.gremlin.hadoop.structure.io.VertexWritable;
diff --git a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/PersistedInputRDD.java b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/PersistedInputRDD.java
index 00237db..0b6aa2d 100644
--- a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/PersistedInputRDD.java
+++ b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/PersistedInputRDD.java
@@ -19,7 +19,7 @@
 
 package org.apache.tinkerpop.gremlin.spark.structure.io;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.spark.api.java.JavaPairRDD;
 import org.apache.spark.api.java.JavaRDD;
 import org.apache.spark.api.java.JavaSparkContext;
diff --git a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/PersistedOutputRDD.java b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/PersistedOutputRDD.java
index 6eb6673..5c76391 100644
--- a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/PersistedOutputRDD.java
+++ b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/PersistedOutputRDD.java
@@ -19,7 +19,7 @@
 
 package org.apache.tinkerpop.gremlin.spark.structure.io;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.spark.api.java.JavaPairRDD;
 import org.apache.spark.storage.StorageLevel;
 import org.apache.tinkerpop.gremlin.hadoop.Constants;
diff --git a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/SparkContextStorage.java b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/SparkContextStorage.java
index e02b159..4d72f70 100644
--- a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/SparkContextStorage.java
+++ b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/SparkContextStorage.java
@@ -19,8 +19,8 @@
 
 package org.apache.tinkerpop.gremlin.spark.structure.io;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.hadoop.mapreduce.InputFormat;
 import org.apache.spark.SparkContext;
 import org.apache.spark.api.java.JavaSparkContext;
diff --git a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/gryo/GryoRegistrator.java b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/gryo/GryoRegistrator.java
index 13fc787..d0e46da 100644
--- a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/gryo/GryoRegistrator.java
+++ b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/gryo/GryoRegistrator.java
@@ -198,8 +198,8 @@
         // the ordering of the existing entries in that constructor, since not all
         // of the entries are for TinkerPop (and the ordering is significant).
         try {
-            m.put(Class.forName("scala.reflect.ClassTag$$anon$1"), new JavaSerializer());
-            m.put(Class.forName("scala.reflect.ManifestFactory$$anon$1"), new JavaSerializer());
+            m.put(Class.forName("scala.reflect.ManifestFactory$AnyManifest"), new JavaSerializer());
+            m.put(Class.forName("scala.reflect.ClassTag$GenericClassTag"), new JavaSerializer());
             m.put(Class.forName("org.apache.spark.internal.io.FileCommitProtocol$TaskCommitMessage"), new JavaSerializer());
             m.put(Class.forName("org.apache.spark.internal.io.FileCommitProtocol$EmptyTaskCommitMessage$"), new JavaSerializer());
 
diff --git a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/gryo/GryoSerializer.java b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/gryo/GryoSerializer.java
index ec5ae9b..2dce832 100644
--- a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/gryo/GryoSerializer.java
+++ b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/gryo/GryoSerializer.java
@@ -20,8 +20,8 @@
 package org.apache.tinkerpop.gremlin.spark.structure.io.gryo;
 
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.spark.SparkConf;
 import org.apache.spark.api.python.PythonBroadcast;
 import org.apache.spark.broadcast.TorrentBroadcast;
@@ -115,7 +115,6 @@
 
     private static Configuration makeApacheConfiguration(final SparkConf sparkConfiguration) {
         final BaseConfiguration apacheConfiguration = new BaseConfiguration();
-        apacheConfiguration.setDelimiterParsingDisabled(true);
         for (final Tuple2<String, String> tuple : sparkConfiguration.getAll()) {
             apacheConfiguration.setProperty(tuple._1(), tuple._2());
         }
@@ -139,8 +138,8 @@
                 super.register(GryoIo.class, TorrentBroadcast.class, null);
                 super.register(GryoIo.class, PythonBroadcast.class, null);
                 super.register(GryoIo.class, BoxedUnit.class, null);
-                super.register(GryoIo.class, Class.forName("scala.reflect.ClassTag$$anon$1"), new JavaSerializer());
-                super.register(GryoIo.class, Class.forName("scala.reflect.ManifestFactory$$anon$1"), new JavaSerializer());
+                super.register(GryoIo.class, Class.forName("scala.reflect.ManifestFactory$AnyManifest"), new JavaSerializer());
+                super.register(GryoIo.class, Class.forName("scala.reflect.ClassTag$GenericClassTag"), new JavaSerializer());
                 super.register(GryoIo.class, Class.forName("org.apache.spark.internal.io.FileCommitProtocol$TaskCommitMessage"), new JavaSerializer());
                 super.register(GryoIo.class, Class.forName("org.apache.spark.internal.io.FileCommitProtocol$EmptyTaskCommitMessage$"), new JavaSerializer());
                 super.register(GryoIo.class, Class.forName("scala.collection.immutable.Map$EmptyMap$"), new JavaSerializer());
diff --git a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/gryo/kryoshim/unshaded/UnshadedKryoShimService.java b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/gryo/kryoshim/unshaded/UnshadedKryoShimService.java
index e1a4600..77cbf20 100644
--- a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/gryo/kryoshim/unshaded/UnshadedKryoShimService.java
+++ b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/gryo/kryoshim/unshaded/UnshadedKryoShimService.java
@@ -21,7 +21,7 @@
 import com.esotericsoftware.kryo.Kryo;
 import com.esotericsoftware.kryo.io.Input;
 import com.esotericsoftware.kryo.io.Output;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.spark.SparkConf;
 import org.apache.spark.serializer.KryoSerializer;
 import org.apache.tinkerpop.gremlin.spark.structure.Spark;
diff --git a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/AbstractSparkTest.java b/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/AbstractSparkTest.java
index 2f3eb6f..f9ada20 100644
--- a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/AbstractSparkTest.java
+++ b/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/AbstractSparkTest.java
@@ -19,8 +19,8 @@
 
 package org.apache.tinkerpop.gremlin.spark;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.spark.launcher.SparkLauncher;
 import org.apache.tinkerpop.gremlin.hadoop.Constants;
 import org.apache.tinkerpop.gremlin.hadoop.structure.HadoopGraph;
@@ -51,7 +51,6 @@
 
     protected Configuration getBaseConfiguration() {
         final BaseConfiguration configuration = new BaseConfiguration();
-        configuration.setDelimiterParsingDisabled(true);
         configuration.setProperty(SparkLauncher.SPARK_MASTER, "local[4]");
         configuration.setProperty(Constants.SPARK_SERIALIZER, GryoSerializer.class.getCanonicalName());
         configuration.setProperty(Constants.SPARK_KRYO_REGISTRATION_REQUIRED, true);
diff --git a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/process/computer/LocalPropertyTest.java b/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/process/computer/LocalPropertyTest.java
index c6b6e8a..829c405 100644
--- a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/process/computer/LocalPropertyTest.java
+++ b/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/process/computer/LocalPropertyTest.java
@@ -19,8 +19,8 @@
 
 package org.apache.tinkerpop.gremlin.spark.process.computer;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.spark.SparkConf;
 import org.apache.spark.SparkContext;
 import org.apache.spark.api.java.JavaSparkContext;
diff --git a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/process/computer/traversal/strategy/optimization/SparkInterceptorStrategyTest.java b/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/process/computer/traversal/strategy/optimization/SparkInterceptorStrategyTest.java
index 73d47db..b1d58a6 100644
--- a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/process/computer/traversal/strategy/optimization/SparkInterceptorStrategyTest.java
+++ b/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/process/computer/traversal/strategy/optimization/SparkInterceptorStrategyTest.java
@@ -19,7 +19,7 @@
 
 package org.apache.tinkerpop.gremlin.spark.process.computer.traversal.strategy.optimization;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.TestHelper;
 import org.apache.tinkerpop.gremlin.hadoop.Constants;
 import org.apache.tinkerpop.gremlin.hadoop.structure.io.gryo.GryoInputFormat;
@@ -69,9 +69,9 @@
         ///
         Graph graph = GraphFactory.open(configuration);
         GraphTraversalSource g = graph.traversal().withComputer().withoutStrategies(SparkSingleIterationStrategy.class);
-        assertFalse(g.getStrategies().toList().contains(SparkSingleIterationStrategy.instance()));
+        assertFalse(g.getStrategies().getStrategy(SparkSingleIterationStrategy.class).isPresent());
         assertFalse(g.V().count().explain().toString().contains(SparkSingleIterationStrategy.class.getSimpleName()));
-        assertTrue(g.getStrategies().toList().contains(SparkInterceptorStrategy.instance()));
+        assertTrue(g.getStrategies().getStrategy(SparkInterceptorStrategy.class).isPresent());
         assertTrue(g.V().count().explain().toString().contains(SparkInterceptorStrategy.class.getSimpleName()));
         /// groupCount(m)-test
         Traversal.Admin<Vertex, Long> traversal = g.V().groupCount("m").by(T.label).count().asAdmin();
@@ -97,9 +97,9 @@
         ///
         Graph graph = GraphFactory.open(configuration);
         GraphTraversalSource g = graph.traversal().withComputer().withoutStrategies(SparkSingleIterationStrategy.class);
-        assertFalse(g.getStrategies().toList().contains(SparkSingleIterationStrategy.instance()));
+        assertFalse(g.getStrategies().getStrategy(SparkSingleIterationStrategy.class).isPresent());
         assertFalse(g.V().count().explain().toString().contains(SparkSingleIterationStrategy.class.getSimpleName()));
-        assertTrue(g.getStrategies().toList().contains(SparkInterceptorStrategy.instance()));
+        assertTrue(g.getStrategies().getStrategy(SparkInterceptorStrategy.class).isPresent());
         assertTrue(g.V().count().explain().toString().contains(SparkInterceptorStrategy.class.getSimpleName()));
         /// SparkCountInterceptor matches
         test(SparkStarBarrierInterceptor.class, 6l, g.V().count());
diff --git a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/process/computer/traversal/strategy/optimization/SparkSingleIterationStrategyTest.java b/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/process/computer/traversal/strategy/optimization/SparkSingleIterationStrategyTest.java
index da63560..6202f33 100644
--- a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/process/computer/traversal/strategy/optimization/SparkSingleIterationStrategyTest.java
+++ b/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/process/computer/traversal/strategy/optimization/SparkSingleIterationStrategyTest.java
@@ -19,7 +19,7 @@
 
 package org.apache.tinkerpop.gremlin.spark.process.computer.traversal.strategy.optimization;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.TestHelper;
 import org.apache.tinkerpop.gremlin.hadoop.Constants;
 import org.apache.tinkerpop.gremlin.hadoop.structure.io.gryo.GryoInputFormat;
@@ -88,11 +88,11 @@
 
         Graph graph = GraphFactory.open(configuration);
         GraphTraversalSource g = graph.traversal().withComputer().withoutStrategies(SparkInterceptorStrategy.class, MessagePassingReductionStrategy.class);
-        assertFalse(g.getStrategies().toList().contains(SparkInterceptorStrategy.instance()));
+        assertFalse(g.getStrategies().getStrategy(SparkInterceptorStrategy.class).isPresent());
         assertFalse(g.V().count().explain().getStrategyTraversals().stream().filter(pair -> pair.getValue0() instanceof SparkInterceptorStrategy).findAny().isPresent());
-        assertFalse(g.getStrategies().toList().contains(MessagePassingReductionStrategy.instance()));
+        assertFalse(g.getStrategies().getStrategy(MessagePassingReductionStrategy.class).isPresent());
         assertFalse(g.V().count().explain().getStrategyTraversals().stream().filter(pair -> pair.getValue0() instanceof MessagePassingReductionStrategy).findAny().isPresent());
-        assertTrue(g.getStrategies().toList().contains(SparkSingleIterationStrategy.instance()));
+        assertTrue(g.getStrategies().getStrategy(SparkSingleIterationStrategy.class).isPresent());
         assertTrue(g.V().count().explain().getStrategyTraversals().stream().filter(pair -> pair.getValue0() instanceof SparkSingleIterationStrategy).findAny().isPresent());
 
         test(true, g.V().limit(10));
@@ -116,11 +116,11 @@
 
         graph = GraphFactory.open(configuration);
         g = graph.traversal().withComputer().withoutStrategies(SparkInterceptorStrategy.class).withStrategies(MessagePassingReductionStrategy.instance());
-        assertFalse(g.getStrategies().toList().contains(SparkInterceptorStrategy.instance()));
+        assertFalse(g.getStrategies().getStrategy(SparkInterceptorStrategy.class).isPresent());
         assertFalse(g.V().count().explain().getStrategyTraversals().stream().filter(pair -> pair.getValue0() instanceof SparkInterceptorStrategy).findAny().isPresent());
-        assertTrue(g.getStrategies().toList().contains(MessagePassingReductionStrategy.instance()));
+        assertTrue(g.getStrategies().getStrategy(MessagePassingReductionStrategy.class).isPresent());
         assertTrue(g.V().count().explain().getStrategyTraversals().stream().filter(pair -> pair.getValue0() instanceof MessagePassingReductionStrategy).findAny().isPresent());
-        assertTrue(g.getStrategies().toList().contains(SparkSingleIterationStrategy.instance()));
+        assertTrue(g.getStrategies().getStrategy(SparkSingleIterationStrategy.class).isPresent());
         assertTrue(g.V().count().explain().getStrategyTraversals().stream().filter(pair -> pair.getValue0() instanceof SparkSingleIterationStrategy).findAny().isPresent());
 
         test(true, g.V().limit(10));
diff --git a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/SparkTest.java b/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/SparkTest.java
index 539f67a..5aa78a4 100644
--- a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/SparkTest.java
+++ b/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/SparkTest.java
@@ -19,8 +19,8 @@
 
 package org.apache.tinkerpop.gremlin.spark.structure;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.spark.rdd.RDD;
 import org.apache.tinkerpop.gremlin.TestHelper;
 import org.apache.tinkerpop.gremlin.hadoop.Constants;
diff --git a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/io/ExampleInputRDD.java b/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/io/ExampleInputRDD.java
index 86c7610..7ca67a1 100644
--- a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/io/ExampleInputRDD.java
+++ b/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/io/ExampleInputRDD.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.spark.structure.io;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.spark.api.java.JavaPairRDD;
 import org.apache.spark.api.java.JavaSparkContext;
 import org.apache.tinkerpop.gremlin.hadoop.structure.io.VertexWritable;
diff --git a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/io/ExampleOutputRDD.java b/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/io/ExampleOutputRDD.java
index ed36886..4ca0a69 100644
--- a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/io/ExampleOutputRDD.java
+++ b/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/io/ExampleOutputRDD.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.spark.structure.io;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.spark.api.java.JavaPairRDD;
 import org.apache.tinkerpop.gremlin.hadoop.structure.io.VertexWritable;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
diff --git a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/io/InputOutputRDDTest.java b/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/io/InputOutputRDDTest.java
index e1098de..337b2b5 100644
--- a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/io/InputOutputRDDTest.java
+++ b/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/io/InputOutputRDDTest.java
@@ -18,8 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.spark.structure.io;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.TestHelper;
 import org.apache.tinkerpop.gremlin.hadoop.Constants;
 import org.apache.tinkerpop.gremlin.hadoop.structure.HadoopGraph;
diff --git a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/io/InputRDDTest.java b/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/io/InputRDDTest.java
index 8a8392a..11c4f48 100644
--- a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/io/InputRDDTest.java
+++ b/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/io/InputRDDTest.java
@@ -18,8 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.spark.structure.io;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.TestHelper;
 import org.apache.tinkerpop.gremlin.hadoop.Constants;
 import org.apache.tinkerpop.gremlin.hadoop.structure.HadoopGraph;
diff --git a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/io/OutputRDDTest.java b/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/io/OutputRDDTest.java
index 617b268..7042a6c 100644
--- a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/io/OutputRDDTest.java
+++ b/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/io/OutputRDDTest.java
@@ -18,8 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.spark.structure.io;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.TestHelper;
 import org.apache.tinkerpop.gremlin.hadoop.Constants;
 import org.apache.tinkerpop.gremlin.hadoop.structure.HadoopGraph;
diff --git a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/io/PersistedInputOutputRDDIntegrateTest.java b/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/io/PersistedInputOutputRDDIntegrateTest.java
index 07f3223..f26efbc 100644
--- a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/io/PersistedInputOutputRDDIntegrateTest.java
+++ b/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/io/PersistedInputOutputRDDIntegrateTest.java
@@ -19,8 +19,7 @@
 
 package org.apache.tinkerpop.gremlin.spark.structure.io;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.spark.storage.StorageLevel;
 import org.apache.tinkerpop.gremlin.TestHelper;
 import org.apache.tinkerpop.gremlin.hadoop.Constants;
@@ -28,7 +27,6 @@
 import org.apache.tinkerpop.gremlin.hadoop.structure.io.gryo.GryoOutputFormat;
 import org.apache.tinkerpop.gremlin.process.computer.Computer;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
-import org.apache.tinkerpop.gremlin.process.computer.bulkloading.BulkLoaderVertexProgram;
 import org.apache.tinkerpop.gremlin.process.computer.ranking.pagerank.PageRankMapReduce;
 import org.apache.tinkerpop.gremlin.process.computer.ranking.pagerank.PageRankVertexProgram;
 import org.apache.tinkerpop.gremlin.process.computer.traversal.TraversalVertexProgram;
@@ -38,9 +36,7 @@
 import org.apache.tinkerpop.gremlin.spark.process.computer.SparkHadoopGraphProvider;
 import org.apache.tinkerpop.gremlin.spark.structure.Spark;
 import org.apache.tinkerpop.gremlin.structure.Graph;
-import org.apache.tinkerpop.gremlin.structure.io.IoCore;
 import org.apache.tinkerpop.gremlin.structure.util.GraphFactory;
-import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
 import org.junit.Test;
 
 import java.util.Arrays;
@@ -208,86 +204,6 @@
     }
 
     @Test
-    public void testBulkLoaderVertexProgramChain() throws Exception {
-        Spark.create("local[4]");
-        final String rddName = TestHelper.makeTestDataDirectory(PersistedInputOutputRDDIntegrateTest.class, UUID.randomUUID().toString());
-        final Configuration readConfiguration = super.getBaseConfiguration();
-        readConfiguration.setProperty(Constants.GREMLIN_HADOOP_GRAPH_READER, GryoInputFormat.class.getCanonicalName());
-        readConfiguration.setProperty(Constants.GREMLIN_HADOOP_INPUT_LOCATION, SparkHadoopGraphProvider.PATHS.get("tinkerpop-modern-v3d0.kryo"));
-        readConfiguration.setProperty(Constants.GREMLIN_HADOOP_GRAPH_WRITER, PersistedOutputRDD.class.getCanonicalName());
-        readConfiguration.setProperty(Constants.GREMLIN_HADOOP_OUTPUT_LOCATION, rddName);
-        readConfiguration.setProperty(Constants.GREMLIN_SPARK_PERSIST_CONTEXT, true);
-        Graph pageRankGraph = GraphFactory.open(readConfiguration);
-        ///////////////
-        final Configuration writeConfiguration = new BaseConfiguration();
-        writeConfiguration.setProperty(Graph.GRAPH, TinkerGraph.class.getCanonicalName());
-        writeConfiguration.setProperty(TinkerGraph.GREMLIN_TINKERGRAPH_GRAPH_FORMAT, "gryo");
-        writeConfiguration.setProperty(TinkerGraph.GREMLIN_TINKERGRAPH_GRAPH_LOCATION, TestHelper.makeTestDataFile(PersistedInputOutputRDDIntegrateTest.class, "testBulkLoaderVertexProgramChain.kryo"));
-        final Graph bulkLoaderGraph = pageRankGraph.compute(SparkGraphComputer.class).persist(GraphComputer.Persist.VERTEX_PROPERTIES).program(PageRankVertexProgram.build().create(pageRankGraph)).submit().get().graph();
-        bulkLoaderGraph.compute(SparkGraphComputer.class)
-                .persist(GraphComputer.Persist.NOTHING)
-                .workers(1)
-                .configure(Constants.GREMLIN_HADOOP_GRAPH_READER, PersistedInputRDD.class.getCanonicalName())
-                .configure(Constants.GREMLIN_HADOOP_INPUT_LOCATION, rddName)
-                .configure(Constants.GREMLIN_HADOOP_GRAPH_WRITER, null)
-                .configure(Constants.GREMLIN_HADOOP_OUTPUT_LOCATION, null)
-                .program(BulkLoaderVertexProgram.build().userSuppliedIds(true).writeGraph(writeConfiguration).create(bulkLoaderGraph))
-                .submit().get();
-        ////
-        assertTrue(Spark.hasRDD(Constants.getGraphLocation(rddName)));
-        assertEquals(1, Spark.getContext().getPersistentRDDs().size());
-        ////
-        final Graph graph = TinkerGraph.open();
-        final GraphTraversalSource g = graph.traversal();
-        graph.io(IoCore.gryo()).readGraph(TestHelper.makeTestDataFile(PersistedInputOutputRDDIntegrateTest.class, "testBulkLoaderVertexProgramChain.kryo"));
-        assertEquals(6l, g.V().count().next().longValue());
-        assertEquals(0l, g.E().count().next().longValue());
-        assertEquals("marko", g.V().has("name", "marko").values("name").next());
-        assertEquals(6l, g.V().values(PageRankVertexProgram.PAGE_RANK).count().next().longValue());
-        ////
-        Spark.close();
-    }
-
-    @Test
-    public void testBulkLoaderVertexProgramChainWithInputOutputHelperMapping() throws Exception {
-        Spark.create("local[4]");
-
-        final String rddName = TestHelper.makeTestDataDirectory(PersistedInputOutputRDDIntegrateTest.class, UUID.randomUUID().toString());
-        final Configuration readConfiguration = super.getBaseConfiguration();
-        readConfiguration.setProperty(Constants.GREMLIN_HADOOP_GRAPH_READER, GryoInputFormat.class.getCanonicalName());
-        readConfiguration.setProperty(Constants.GREMLIN_HADOOP_INPUT_LOCATION, SparkHadoopGraphProvider.PATHS.get("tinkerpop-modern-v3d0.kryo"));
-        readConfiguration.setProperty(Constants.GREMLIN_HADOOP_GRAPH_WRITER, PersistedOutputRDD.class.getCanonicalName());
-        readConfiguration.setProperty(Constants.GREMLIN_HADOOP_OUTPUT_LOCATION, rddName);
-        readConfiguration.setProperty(Constants.GREMLIN_SPARK_PERSIST_CONTEXT, true);
-        Graph pageRankGraph = GraphFactory.open(readConfiguration);
-        ///////////////
-        final Configuration writeConfiguration = new BaseConfiguration();
-        writeConfiguration.setProperty(Graph.GRAPH, TinkerGraph.class.getCanonicalName());
-        writeConfiguration.setProperty(TinkerGraph.GREMLIN_TINKERGRAPH_GRAPH_FORMAT, "gryo");
-        writeConfiguration.setProperty(TinkerGraph.GREMLIN_TINKERGRAPH_GRAPH_LOCATION, TestHelper.makeTestDataFile(PersistedInputOutputRDDIntegrateTest.class, "testBulkLoaderVertexProgramChainWithInputOutputHelperMapping.kryo"));
-        final Graph bulkLoaderGraph = pageRankGraph.compute(SparkGraphComputer.class).persist(GraphComputer.Persist.EDGES).program(PageRankVertexProgram.build().create(pageRankGraph)).submit().get().graph();
-        bulkLoaderGraph.compute(SparkGraphComputer.class)
-                .persist(GraphComputer.Persist.NOTHING)
-                .workers(1)
-                .program(BulkLoaderVertexProgram.build().userSuppliedIds(true).writeGraph(writeConfiguration).create(bulkLoaderGraph))
-                .submit().get();
-        ////
-        Spark.create(readConfiguration);
-        assertTrue(Spark.hasRDD(Constants.getGraphLocation(rddName)));
-        assertEquals(1, Spark.getContext().getPersistentRDDs().size());
-        ////
-        final Graph graph = TinkerGraph.open();
-        final GraphTraversalSource g = graph.traversal();
-        graph.io(IoCore.gryo()).readGraph(TestHelper.makeTestDataFile(PersistedInputOutputRDDIntegrateTest.class, "testBulkLoaderVertexProgramChainWithInputOutputHelperMapping.kryo"));
-        assertEquals(6l, g.V().count().next().longValue());
-        assertEquals(6l, g.E().count().next().longValue());
-        assertEquals("marko", g.V().has("name", "marko").values("name").next());
-        assertEquals(6l, g.V().values(PageRankVertexProgram.PAGE_RANK).count().next().longValue());
-        ////
-        Spark.close();
-    }
-
-    @Test
     public void testComplexChain() throws Exception {
         Spark.create("local[4]");
 
diff --git a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/io/ToyGraphInputRDD.java b/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/io/ToyGraphInputRDD.java
index 90764ce..d167756 100644
--- a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/io/ToyGraphInputRDD.java
+++ b/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/io/ToyGraphInputRDD.java
@@ -19,7 +19,7 @@
 
 package org.apache.tinkerpop.gremlin.spark.structure.io;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.spark.api.java.JavaPairRDD;
 import org.apache.spark.api.java.JavaSparkContext;
 import org.apache.tinkerpop.gremlin.hadoop.Constants;
diff --git a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/io/gryo/GryoSerializerIntegrateTest.java b/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/io/gryo/GryoSerializerIntegrateTest.java
index c3ac83f..c3a01fb 100644
--- a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/io/gryo/GryoSerializerIntegrateTest.java
+++ b/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/structure/io/gryo/GryoSerializerIntegrateTest.java
@@ -19,7 +19,7 @@
 
 package org.apache.tinkerpop.gremlin.spark.structure.io.gryo;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.TestHelper;
 import org.apache.tinkerpop.gremlin.hadoop.Constants;
 import org.apache.tinkerpop.gremlin.hadoop.structure.io.gryo.GryoInputFormat;
diff --git a/sparql-gremlin/pom.xml b/sparql-gremlin/pom.xml
index 165f707..e051b6b 100644
--- a/sparql-gremlin/pom.xml
+++ b/sparql-gremlin/pom.xml
@@ -6,7 +6,7 @@
     <parent>
         <artifactId>tinkerpop</artifactId>
         <groupId>org.apache.tinkerpop</groupId>
-        <version>3.4.12-SNAPSHOT</version>
+        <version>3.5.1-SNAPSHOT</version>
     </parent>
     <artifactId>sparql-gremlin</artifactId>
     <name>Apache TinkerPop :: SPARQL Gremlin</name>
@@ -41,7 +41,7 @@
         </dependency>
         <dependency>
             <groupId>org.hamcrest</groupId>
-            <artifactId>hamcrest-all</artifactId>
+            <artifactId>hamcrest</artifactId>
             <scope>test</scope>
         </dependency>
     </dependencies>
diff --git a/sparql-gremlin/src/main/java/org/apache/tinkerpop/gremlin/sparql/SparqlToGremlinCompiler.java b/sparql-gremlin/src/main/java/org/apache/tinkerpop/gremlin/sparql/SparqlToGremlinCompiler.java
index 1dbb173..62e9647 100644
--- a/sparql-gremlin/src/main/java/org/apache/tinkerpop/gremlin/sparql/SparqlToGremlinCompiler.java
+++ b/sparql-gremlin/src/main/java/org/apache/tinkerpop/gremlin/sparql/SparqlToGremlinCompiler.java
@@ -218,7 +218,7 @@
 
                 // by default, the sort will be ascending. getDirection() returns -2 if the DESC/ASC isn't
                 // supplied - weird
-                orderingIndex.put(expr.getVarName(), sortCondition.getDirection() == -1 ? Order.decr : Order.incr);
+                orderingIndex.put(expr.getVarName(), sortCondition.getDirection() == -1 ? Order.desc : Order.asc);
             }
         }
 
diff --git a/sparql-gremlin/src/main/java/org/apache/tinkerpop/gremlin/sparql/process/traversal/dsl/sparql/SparqlTraversalSource.java b/sparql-gremlin/src/main/java/org/apache/tinkerpop/gremlin/sparql/process/traversal/dsl/sparql/SparqlTraversalSource.java
index 79812bb..bb8d70b 100644
--- a/sparql-gremlin/src/main/java/org/apache/tinkerpop/gremlin/sparql/process/traversal/dsl/sparql/SparqlTraversalSource.java
+++ b/sparql-gremlin/src/main/java/org/apache/tinkerpop/gremlin/sparql/process/traversal/dsl/sparql/SparqlTraversalSource.java
@@ -18,12 +18,9 @@
  */
 package org.apache.tinkerpop.gremlin.sparql.process.traversal.dsl.sparql;
 
-import org.apache.commons.configuration.Configuration;
 import org.apache.tinkerpop.gremlin.process.computer.Computer;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
 import org.apache.tinkerpop.gremlin.process.remote.RemoteConnection;
-import org.apache.tinkerpop.gremlin.process.remote.traversal.strategy.decoration.RemoteStrategy;
-import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
@@ -33,9 +30,6 @@
 import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.InjectStep;
 import org.apache.tinkerpop.gremlin.sparql.process.traversal.strategy.SparqlStrategy;
 import org.apache.tinkerpop.gremlin.structure.Graph;
-import org.apache.tinkerpop.gremlin.structure.Transaction;
-import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
-import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
 
 import java.util.function.BinaryOperator;
 import java.util.function.Supplier;
@@ -174,21 +168,6 @@
         return (SparqlTraversalSource) super.withoutStrategies(traversalStrategyClasses);
     }
 
-    @Override
-    public SparqlTraversalSource withRemote(final Configuration conf) {
-        return (SparqlTraversalSource) super.withRemote(conf);
-    }
-
-    @Override
-    public SparqlTraversalSource withRemote(final String configFile) throws Exception {
-        return (SparqlTraversalSource) super.withRemote(configFile);
-    }
-
-    @Override
-    public SparqlTraversalSource withRemote(final RemoteConnection connection) {
-        return (SparqlTraversalSource) super.withRemote(connection);
-    }
-
     /**
      * The start step for a SPARQL based traversal that accepts a string representation of the query to execute.
      */
diff --git a/sparql-gremlin/src/main/java/org/apache/tinkerpop/gremlin/sparql/process/traversal/strategy/SparqlStrategy.java b/sparql-gremlin/src/main/java/org/apache/tinkerpop/gremlin/sparql/process/traversal/strategy/SparqlStrategy.java
index 7a62e31..a4a95cc 100644
--- a/sparql-gremlin/src/main/java/org/apache/tinkerpop/gremlin/sparql/process/traversal/strategy/SparqlStrategy.java
+++ b/sparql-gremlin/src/main/java/org/apache/tinkerpop/gremlin/sparql/process/traversal/strategy/SparqlStrategy.java
@@ -65,7 +65,7 @@
 
     @Override
     public void apply(final Traversal.Admin<?, ?> traversal) {
-        if (!(traversal.getParent() instanceof EmptyStep))
+        if (!(traversal.isRoot()))
             return;
 
         // assumes that the traversal starts with the single inject step that holds the sparql query
diff --git a/tinkergraph-gremlin/pom.xml b/tinkergraph-gremlin/pom.xml
index 6b926da..67db08b 100644
--- a/tinkergraph-gremlin/pom.xml
+++ b/tinkergraph-gremlin/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.apache.tinkerpop</groupId>
         <artifactId>tinkerpop</artifactId>
-        <version>3.4.12-SNAPSHOT</version>
+        <version>3.5.1-SNAPSHOT</version>
     </parent>
     <artifactId>tinkergraph-gremlin</artifactId>
     <name>Apache TinkerPop :: TinkerGraph Gremlin</name>
diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/computer/TinkerMessenger.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/computer/TinkerMessenger.java
index 3e49c34..dd993c1 100644
--- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/computer/TinkerMessenger.java
+++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/computer/TinkerMessenger.java
@@ -66,7 +66,7 @@
                 final MessageScope.Local<M> localMessageScope = (MessageScope.Local<M>) messageScope;
                 final Traversal.Admin<Vertex, Edge> incidentTraversal = TinkerMessenger.setVertexStart(localMessageScope.getIncidentTraversal().get().asAdmin(), this.vertex);
                 final Direction direction = TinkerMessenger.getDirection(incidentTraversal);
-                final Edge[] edge = new Edge[1]; // simulates storage side-effects available in Gremlin, but not Java8 streams
+                final Edge[] edge = new Edge[1]; // simulates storage side-effects available in Gremlin, but not Java streams
                 multiIterator.addIterator(StreamSupport.stream(Spliterators.spliteratorUnknownSize(VertexProgramHelper.reverse(incidentTraversal.asAdmin()), Spliterator.IMMUTABLE | Spliterator.SIZED), false)
                         .map((Edge e) -> {
                             edge[0] = e;
diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphCountStrategy.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphCountStrategy.java
index 55e6b55..53b3eca 100644
--- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphCountStrategy.java
+++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphCountStrategy.java
@@ -25,9 +25,8 @@
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.CountGlobalStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.GraphStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.MapStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.NoOpBarrierStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.AggregateStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.AggregateGlobalStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.IdentityStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.SideEffectStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.CollectingBarrierStep;
@@ -61,7 +60,7 @@
 
     @Override
     public void apply(final Traversal.Admin<?, ?> traversal) {
-        if (!(traversal.getParent() instanceof EmptyStep) || TraversalHelper.onGraphComputer(traversal))
+        if (!(traversal.isRoot()) || TraversalHelper.onGraphComputer(traversal))
             return;
         final List<Step> steps = traversal.getSteps();
         if (steps.size() < 2 ||
@@ -76,7 +75,7 @@
                     current instanceof NoOpBarrierStep ||
                     current instanceof CollectingBarrierStep) ||
                     (current instanceof TraversalParent &&
-                            TraversalHelper.anyStepRecursively(s -> (s instanceof SideEffectStep || s instanceof AggregateStep), (TraversalParent) current)))
+                            TraversalHelper.anyStepRecursively(s -> (s instanceof SideEffectStep || s instanceof AggregateGlobalStep), (TraversalParent) current)))
                 return;
         }
         final Class<? extends Element> elementClass = ((GraphStep<?, ?>) steps.get(0)).getReturnClass();
diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerEdge.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerEdge.java
index bcfe485..02f7ede 100644
--- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerEdge.java
+++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerEdge.java
@@ -43,11 +43,13 @@
     protected Map<String, Property> properties;
     protected final Vertex inVertex;
     protected final Vertex outVertex;
+    private final boolean allowNullPropertyValues;
 
     protected TinkerEdge(final Object id, final Vertex outVertex, final String label, final Vertex inVertex) {
         super(id, label);
         this.outVertex = outVertex;
         this.inVertex = inVertex;
+        this.allowNullPropertyValues = outVertex.graph().features().edge().supportsNullPropertyValues();
         TinkerHelper.autoUpdateIndex(this, T.label.getAccessor(), this.label, null);
     }
 
@@ -55,6 +57,12 @@
     public <V> Property<V> property(final String key, final V value) {
         if (this.removed) throw elementAlreadyRemoved(Edge.class, id);
         ElementHelper.validateProperty(key, value);
+
+        if (!allowNullPropertyValues && null == value) {
+            properties(key).forEachRemaining(Property::remove);
+            return Property.empty();
+        }
+
         final Property oldProperty = super.property(key);
         final Property<V> newProperty = new TinkerProperty<>(this, key, value);
         if (null == this.properties) this.properties = new HashMap<>();
diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerFactory.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerFactory.java
index 6c0f1b2..61cc7a8 100644
--- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerFactory.java
+++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerFactory.java
@@ -18,8 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.tinkergraph.structure;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
 import org.apache.tinkerpop.gremlin.structure.T;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java
index 5dbc311..6f4f821 100644
--- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java
+++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java
@@ -18,8 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.tinkergraph.structure;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
 import org.apache.tinkerpop.gremlin.structure.Edge;
@@ -83,6 +83,7 @@
     public static final String GREMLIN_TINKERGRAPH_DEFAULT_VERTEX_PROPERTY_CARDINALITY = "gremlin.tinkergraph.defaultVertexPropertyCardinality";
     public static final String GREMLIN_TINKERGRAPH_GRAPH_LOCATION = "gremlin.tinkergraph.graphLocation";
     public static final String GREMLIN_TINKERGRAPH_GRAPH_FORMAT = "gremlin.tinkergraph.graphFormat";
+    public static final String GREMLIN_TINKERGRAPH_ALLOW_NULL_PROPERTY_VALUES = "gremlin.tinkergraph.allowNullPropertyValues";
 
     private final TinkerGraphFeatures features = new TinkerGraphFeatures();
 
@@ -99,6 +100,7 @@
     protected final IdManager<?> edgeIdManager;
     protected final IdManager<?> vertexPropertyIdManager;
     protected final VertexProperty.Cardinality defaultVertexPropertyCardinality;
+    protected final boolean allowNullPropertyValues;
 
     private final Configuration configuration;
     private final String graphLocation;
@@ -114,6 +116,7 @@
         vertexPropertyIdManager = selectIdManager(configuration, GREMLIN_TINKERGRAPH_VERTEX_PROPERTY_ID_MANAGER, VertexProperty.class);
         defaultVertexPropertyCardinality = VertexProperty.Cardinality.valueOf(
                 configuration.getString(GREMLIN_TINKERGRAPH_DEFAULT_VERTEX_PROPERTY_CARDINALITY, VertexProperty.Cardinality.single.name()));
+        allowNullPropertyValues = configuration.getBoolean(GREMLIN_TINKERGRAPH_ALLOW_NULL_PROPERTY_VALUES, false);
 
         graphLocation = configuration.getString(GREMLIN_TINKERGRAPH_GRAPH_LOCATION, null);
         graphFormat = configuration.getString(GREMLIN_TINKERGRAPH_GRAPH_FORMAT, null);
@@ -385,6 +388,11 @@
         }
 
         @Override
+        public boolean supportsNullPropertyValues() {
+            return allowNullPropertyValues;
+        }
+
+        @Override
         public Features.VertexPropertyFeatures properties() {
             return vertexPropertyFeatures;
         }
@@ -411,6 +419,11 @@
         }
 
         @Override
+        public boolean supportsNullPropertyValues() {
+            return allowNullPropertyValues;
+        }
+
+        @Override
         public boolean supportsCustomIds() {
             return false;
         }
@@ -449,6 +462,11 @@
         }
 
         @Override
+        public boolean supportsNullPropertyValues() {
+            return allowNullPropertyValues;
+        }
+
+        @Override
         public boolean supportsCustomIds() {
             return false;
         }
diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerIndex.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerIndex.java
index f5872cf..75924da 100644
--- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerIndex.java
+++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerIndex.java
@@ -49,7 +49,7 @@
     protected void put(final String key, final Object value, final T element) {
         Map<Object, Set<T>> keyMap = this.index.get(key);
         if (null == keyMap) {
-            this.index.putIfAbsent(key, new ConcurrentHashMap<Object, Set<T>>());
+            this.index.putIfAbsent(key, new ConcurrentHashMap<>());
             keyMap = this.index.get(key);
         }
         Set<T> objects = keyMap.get(value);
@@ -65,7 +65,7 @@
         if (null == keyMap) {
             return Collections.emptyList();
         } else {
-            Set<T> set = keyMap.get(value);
+            Set<T> set = keyMap.get(indexable(value));
             if (null == set)
                 return Collections.emptyList();
             else
@@ -78,7 +78,7 @@
         if (null == keyMap) {
             return 0;
         } else {
-            Set<T> set = keyMap.get(value);
+            final Set<T> set = keyMap.get(indexable(value));
             if (null == set)
                 return 0;
             else
@@ -89,7 +89,7 @@
     public void remove(final String key, final Object value, final T element) {
         final Map<Object, Set<T>> keyMap = this.index.get(key);
         if (null != keyMap) {
-            Set<T> objects = keyMap.get(value);
+            final Set<T> objects = keyMap.get(indexable(value));
             if (null != objects) {
                 objects.remove(element);
                 if (objects.size() == 0) {
@@ -111,17 +111,11 @@
 
     public void autoUpdate(final String key, final Object newValue, final Object oldValue, final T element) {
         if (this.indexedKeys.contains(key)) {
-            if (oldValue != null)
-                this.remove(key, oldValue, element);
+            this.remove(key, oldValue, element);
             this.put(key, newValue, element);
         }
     }
 
-    public void autoRemove(final String key, final Object oldValue, final T element) {
-        if (this.indexedKeys.contains(key))
-            this.remove(key, oldValue, element);
-    }
-
     public void createKeyIndex(final String key) {
         if (null == key)
             throw Graph.Exceptions.argumentCanNotBeNull("key");
@@ -133,8 +127,8 @@
         this.indexedKeys.add(key);
 
         (Vertex.class.isAssignableFrom(this.indexClass) ?
-                this.graph.vertices.values().<T>parallelStream() :
-                this.graph.edges.values().<T>parallelStream())
+                this.graph.vertices.values().parallelStream() :
+                this.graph.edges.values().parallelStream())
                 .map(e -> new Object[]{((T) e).property(key), e})
                 .filter(a -> ((Property) a[0]).isPresent())
                 .forEach(a -> this.put(key, ((Property) a[0]).value(), (T) a[1]));
@@ -147,7 +141,35 @@
         this.indexedKeys.remove(key);
     }
 
+    /**
+     * Provides a way for an index to have a {@code null} value as {@code ConcurrentHashMap} will not allow a
+     * {@code null} key.
+     */
+    public static Object indexable(final Object obj) {
+        return null == obj ? IndexedNull.instance() : obj;
+    }
+
     public Set<String> getIndexedKeys() {
         return this.indexedKeys;
     }
+
+    public static final class IndexedNull {
+        private static final IndexedNull inst = new IndexedNull();
+
+        private IndexedNull() {}
+
+        static IndexedNull instance() {
+            return inst;
+        }
+
+        @Override
+        public int hashCode() {
+            return 751912123;
+        }
+
+        @Override
+        public boolean equals(final Object o) {
+            return o instanceof IndexedNull;
+        }
+    }
 }
diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerIoRegistryV1d0.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerIoRegistryV1d0.java
index d15a4a7..e2140b1 100644
--- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerIoRegistryV1d0.java
+++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerIoRegistryV1d0.java
@@ -18,8 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.tinkergraph.structure;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.structure.Edge;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.structure.io.AbstractIoRegistry;
diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerIoRegistryV2d0.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerIoRegistryV2d0.java
index 18fd549..e6f59c9 100644
--- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerIoRegistryV2d0.java
+++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerIoRegistryV2d0.java
@@ -18,8 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.tinkergraph.structure;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.structure.Edge;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.structure.io.AbstractIoRegistry;
diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerIoRegistryV3d0.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerIoRegistryV3d0.java
index c62d179..6ee68ee 100644
--- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerIoRegistryV3d0.java
+++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerIoRegistryV3d0.java
@@ -18,8 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.tinkergraph.structure;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.structure.Edge;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.structure.io.AbstractIoRegistry;
diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerProperty.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerProperty.java
index 0f7077b..db40346 100644
--- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerProperty.java
+++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerProperty.java
@@ -54,9 +54,12 @@
         return this.value;
     }
 
+    /**
+     * The existence of this object implies the property is present, thus even a {@code null} value means "present".
+     */
     @Override
     public boolean isPresent() {
-        return null != this.value;
+        return true;
     }
 
     @Override
diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerVertex.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerVertex.java
index be08137..1765054 100644
--- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerVertex.java
+++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerVertex.java
@@ -46,10 +46,12 @@
     protected Map<String, Set<Edge>> outEdges;
     protected Map<String, Set<Edge>> inEdges;
     private final TinkerGraph graph;
+    private boolean allowNullPropertyValues;
 
     protected TinkerVertex(final Object id, final String label, final TinkerGraph graph) {
         super(id, label);
         this.graph = graph;
+        this.allowNullPropertyValues = graph.features().vertex().supportsNullPropertyValues();
     }
 
     @Override
@@ -85,6 +87,16 @@
         if (this.removed) throw elementAlreadyRemoved(Vertex.class, id);
         ElementHelper.legalPropertyKeyValueArray(keyValues);
         ElementHelper.validateProperty(key, value);
+
+        // if we don't allow null property values and the value is null then the key can be removed but only if the
+        // cardinality is single. if it is list/set then we can just ignore the null.
+        if (!allowNullPropertyValues && null == value) {
+            final VertexProperty.Cardinality card = null == cardinality ? graph.features().vertex().getCardinality(key) : cardinality;
+            if (VertexProperty.Cardinality.single == card)
+                properties(key).forEachRemaining(VertexProperty::remove);
+            return VertexProperty.empty();
+        }
+
         final Optional<Object> optionalId = ElementHelper.getIdValue(keyValues);
         final Optional<VertexProperty<V>> optionalVertexProperty = ElementHelper.stageVertexProperty(this, cardinality, key, value, keyValues);
         if (optionalVertexProperty.isPresent()) return optionalVertexProperty.get();
diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerVertexProperty.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerVertexProperty.java
index 3ca871a..f2635df 100644
--- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerVertexProperty.java
+++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerVertexProperty.java
@@ -18,7 +18,6 @@
  */
 package org.apache.tinkerpop.gremlin.tinkergraph.structure;
 
-import org.apache.tinkerpop.gremlin.structure.Element;
 import org.apache.tinkerpop.gremlin.structure.Graph;
 import org.apache.tinkerpop.gremlin.structure.Property;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
@@ -45,6 +44,7 @@
     private final TinkerVertex vertex;
     private final String key;
     private final V value;
+    private final boolean allowNullPropertyValues;
 
     /**
      * This constructor will not validate the ID type against the {@link Graph}.  It will always just use a
@@ -52,12 +52,7 @@
      * with {@link TinkerGraphComputerView}.
      */
     public TinkerVertexProperty(final TinkerVertex vertex, final String key, final V value, final Object... propertyKeyValues) {
-        super(((TinkerGraph) vertex.graph()).vertexPropertyIdManager.getNextId((TinkerGraph) vertex.graph()), key);
-        this.vertex = vertex;
-        this.key = key;
-        this.value = value;
-        ElementHelper.legalPropertyKeyValueArray(propertyKeyValues);
-        ElementHelper.attachProperties(this, propertyKeyValues);
+        this(((TinkerGraph) vertex.graph()).vertexPropertyIdManager.getNextId((TinkerGraph) vertex.graph()), vertex, key, value, propertyKeyValues);
     }
 
     /**
@@ -66,6 +61,10 @@
      */
     public TinkerVertexProperty(final Object id, final TinkerVertex vertex, final String key, final V value, final Object... propertyKeyValues) {
         super(id, key);
+        this.allowNullPropertyValues = vertex.graph().features().vertex().properties().supportsNullPropertyValues();
+        if (!allowNullPropertyValues && null == value)
+            throw new IllegalArgumentException("value cannot be null as feature supportsNullPropertyValues is false");
+
         this.vertex = vertex;
         this.key = key;
         this.value = value;
@@ -117,6 +116,12 @@
     @Override
     public <U> Property<U> property(final String key, final U value) {
         if (this.removed) throw elementAlreadyRemoved(VertexProperty.class, id);
+
+        if ((!allowNullPropertyValues && null == value)) {
+            properties(key).forEachRemaining(Property::remove);
+            return Property.empty();
+        }
+
         final Property<U> property = new TinkerProperty<>(this, key, value);
         if (this.properties == null) this.properties = new HashMap<>();
         this.properties.put(key, property);
@@ -138,7 +143,8 @@
             }
             final AtomicBoolean delete = new AtomicBoolean(true);
             this.vertex.properties(this.key).forEachRemaining(property -> {
-                if (property.value().equals(this.value))
+                final Object currentPropertyValue = property.value();
+                if ((currentPropertyValue != null && currentPropertyValue.equals(this.value) || null == currentPropertyValue && null == this.value))
                     delete.set(false);
             });
             if (delete.get()) TinkerHelper.removeIndex(this.vertex, this.key, this.value);
diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/TinkerGraphProvider.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/TinkerGraphProvider.java
index 0efd240..3254aa1 100644
--- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/TinkerGraphProvider.java
+++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/TinkerGraphProvider.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.tinkergraph;
 
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.AbstractGraphProvider;
 import org.apache.tinkerpop.gremlin.LoadGraphWith;
 import org.apache.tinkerpop.gremlin.TestHelper;
diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/TinkerGraphComputerProvider.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/TinkerGraphComputerProvider.java
index 0efc37a..6121ef7 100644
--- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/TinkerGraphComputerProvider.java
+++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/TinkerGraphComputerProvider.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.tinkergraph.process;
 
-import org.apache.commons.configuration.MapConfiguration;
+import org.apache.commons.configuration2.MapConfiguration;
 import org.apache.tinkerpop.gremlin.GraphProvider;
 import org.apache.tinkerpop.gremlin.TestHelper;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/decoration/HaltedTraverserStrategyTest.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/decoration/HaltedTraverserStrategyTest.java
index 288b4b4..a769f4a 100644
--- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/decoration/HaltedTraverserStrategyTest.java
+++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/decoration/HaltedTraverserStrategyTest.java
@@ -19,7 +19,7 @@
 
 package org.apache.tinkerpop.gremlin.tinkergraph.process.traversal.strategy.decoration;
 
-import org.apache.commons.configuration.MapConfiguration;
+import org.apache.commons.configuration2.MapConfiguration;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.HaltedTraverserStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy;
diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/decoration/OptionsStrategyTest.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/decoration/OptionsStrategyTest.java
index ce39953..02a0b3b 100644
--- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/decoration/OptionsStrategyTest.java
+++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/decoration/OptionsStrategyTest.java
@@ -21,7 +21,7 @@
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.MapStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.ScalarMapStep;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.OptionsStrategy;
 import org.apache.tinkerpop.gremlin.structure.Graph;
 import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
@@ -31,7 +31,7 @@
 import java.util.Collection;
 
 import static org.hamcrest.Matchers.contains;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 
 /**
  * @author Stephen Mallette (http://stephen.genoprime.com)
@@ -54,7 +54,7 @@
 
     private static void assertOptions(final GraphTraversalSource optionedG) {
         GraphTraversal t = optionedG.inject(1);
-        t = t.asAdmin().addStep(new MapStep<Object, Object>(t.asAdmin()) {
+        t = t.asAdmin().addStep(new ScalarMapStep<Object, Object>(t.asAdmin()) {
             @Override
             protected Object map(final Traverser.Admin<Object> traverser) {
                 final OptionsStrategy strategy = traversal.asAdmin().getStrategies().getStrategy(OptionsStrategy.class).get();
diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphIdManagerTest.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphIdManagerTest.java
index f02de1c..e589c5c 100644
--- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphIdManagerTest.java
+++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphIdManagerTest.java
@@ -18,8 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.tinkergraph.structure;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.structure.T;
 import org.apache.tinkerpop.gremlin.structure.Edge;
 import org.apache.tinkerpop.gremlin.structure.Graph;
diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphPlayTest.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphPlayTest.java
index 7a3489a..3489fcf 100644
--- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphPlayTest.java
+++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphPlayTest.java
@@ -22,6 +22,7 @@
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.WithOptions;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.ConsoleMutationListener;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.EventStrategy;
@@ -272,8 +273,13 @@
     @Ignore
     public void testBugs() {
         final GraphTraversalSource g = TinkerFactory.createModern().traversal();
-
+        Object o1 = g.V().map(__.V(1));
         System.out.println(g.V().as("a").both().as("b").dedup("a", "b").by(T.label).select("a", "b").explain());
         System.out.println(g.V().as("a").both().as("b").dedup("a", "b").by(T.label).select("a", "b").toList());
+
+        Traversal<?,?> t =
+                g.V("3").
+                        union(__.repeat(out().simplePath()).times(2).count(),
+                                __.repeat(in().simplePath()).times(2).count());
     }
 }
diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphTest.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphTest.java
index 329a648..9ccdef1 100644
--- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphTest.java
+++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphTest.java
@@ -18,14 +18,15 @@
  */
 package org.apache.tinkerpop.gremlin.tinkergraph.structure;
 
-import org.apache.commons.configuration.BaseConfiguration;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
 import org.apache.tinkerpop.gremlin.GraphHelper;
 import org.apache.tinkerpop.gremlin.TestHelper;
 import org.apache.tinkerpop.gremlin.process.computer.Computer;
 import org.apache.tinkerpop.gremlin.process.traversal.P;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.IdentityRemovalStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReservedKeysVerificationStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.util.Metrics;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalMetrics;
@@ -76,6 +77,7 @@
 import java.util.function.Consumer;
 import java.util.function.Supplier;
 
+import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.greaterThan;
 import static org.hamcrest.Matchers.is;
@@ -746,6 +748,114 @@
         }
     }
 
+    @Test
+    public void shouldProvideClearErrorWhenTryingToMutateEdgeWithCardinality() {
+        final GraphTraversalSource g = TinkerFactory.createModern().traversal();
+
+        try {
+            g.E().property(VertexProperty.Cardinality.single, "k", 100).iterate();
+            fail("Should have thrown an error");
+        } catch (IllegalStateException ise) {
+            assertEquals("Property cardinality can only be set for a Vertex but the traversal encountered TinkerEdge for key: k", ise.getMessage());
+        }
+
+        try {
+            g.E().property(VertexProperty.Cardinality.list, "k", 100).iterate();
+            fail("Should have thrown an error");
+        } catch (IllegalStateException ise) {
+            assertEquals("Property cardinality can only be set for a Vertex but the traversal encountered TinkerEdge for key: k", ise.getMessage());
+        }
+
+        try {
+            g.addE("link").to(__.V(1)).from(__.V(1)).
+                    property(VertexProperty.Cardinality.list, "k", 100).iterate();
+            fail("Should have thrown an error");
+        } catch (IllegalStateException ise) {
+            assertEquals("Multi-property cardinality of [list] can only be set for a Vertex but is being used for addE() with key: k", ise.getMessage());
+        }
+    }
+
+    @Test
+    public void shouldProvideClearErrorWhenPuttingFromToInWrongSpot() {
+        final GraphTraversalSource g = TinkerFactory.createModern().traversal();
+
+        try {
+            g.addE("link").property(VertexProperty.Cardinality.single, "k", 100).out().
+                    to(__.V(1)).from(__.V(1)).iterate();
+            fail("Should have thrown an error");
+        } catch (IllegalArgumentException ise) {
+            assertEquals("The to() step cannot follow VertexStep", ise.getMessage());
+        }
+
+        try {
+            g.addE("link").property("k", 100).out().
+                    from(__.V(1)).to(__.V(1)).iterate();
+            fail("Should have thrown an error");
+        } catch (IllegalArgumentException ise) {
+            assertEquals("The from() step cannot follow VertexStep", ise.getMessage());
+        }
+    }
+
+    @Test
+    public void shouldProvideClearErrorWhenFromOrToDoesNotResolveToVertex() {
+        final GraphTraversalSource g = TinkerFactory.createModern().traversal();
+
+        try {
+            g.addE("link").property(VertexProperty.Cardinality.single, "k", 100).to(__.V(1)).iterate();
+            fail("Should have thrown an error");
+        } catch (IllegalStateException ise) {
+            assertEquals("addE(link) could not find a Vertex for from() - encountered: null", ise.getMessage());
+        }
+
+        try {
+            g.addE("link").property(VertexProperty.Cardinality.single, "k", 100).from(__.V(1)).iterate();
+            fail("Should have thrown an error");
+        } catch (IllegalStateException ise) {
+            assertEquals("addE(link) could not find a Vertex for to() - encountered: null", ise.getMessage());
+        }
+
+        try {
+            g.addE("link").property("k", 100).from(__.V(1)).iterate();
+            fail("Should have thrown an error");
+        } catch (IllegalStateException ise) {
+            assertEquals("addE(link) could not find a Vertex for to() - encountered: null", ise.getMessage());
+        }
+
+        try {
+            g.V(1).values("name").as("a").addE("link").property(VertexProperty.Cardinality.single, "k", 100).from("a").iterate();
+            fail("Should have thrown an error");
+        } catch (IllegalStateException ise) {
+            assertEquals("addE(link) could not find a Vertex for to() - encountered: String", ise.getMessage());
+        }
+
+        try {
+            g.V(1).values("name").as("a").addE("link").property(VertexProperty.Cardinality.single, "k", 100).to("a").iterate();
+            fail("Should have thrown an error");
+        } catch (IllegalStateException ise) {
+            assertEquals("addE(link) could not find a Vertex for to() - encountered: String", ise.getMessage());
+        }
+
+        try {
+            g.V(1).as("v").values("name").as("a").addE("link").property(VertexProperty.Cardinality.single, "k", 100).to("v").from("a").iterate();
+            fail("Should have thrown an error");
+        } catch (IllegalStateException ise) {
+            assertEquals("addE(link) could not find a Vertex for from() - encountered: String", ise.getMessage());
+        }
+    }
+
+    @Test
+    public void shouldWorkWithoutIdentityStrategy() {
+        final Graph graph = TinkerFactory.createModern();
+        final GraphTraversalSource g = traversal().withEmbedded(graph).withoutStrategies(IdentityRemovalStrategy.class);
+        final List<Map<String,Object>> result = g.V().match(__.as("a").out("knows").values("name").as("b")).identity().toList();
+        assertEquals(2, result.size());
+        result.stream().forEach(m -> {
+            assertEquals(2, m.size());
+            assertThat(m.containsKey("a"), is(true));
+            assertThat(m.containsKey("b"), is(true));
+        });
+    }
+
     /**
      * Coerces a {@code Color} to a {@link TinkerGraph} during serialization.  Demonstrates how custom serializers
      * can be developed that can coerce one value to another during serialization.
diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/io/graphson/AbstractTinkerGraphGraphSONTranslatorProvider.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/io/graphson/AbstractTinkerGraphGraphSONTranslatorProvider.java
index 4d4ee00..7f4ebe8 100644
--- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/io/graphson/AbstractTinkerGraphGraphSONTranslatorProvider.java
+++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/io/graphson/AbstractTinkerGraphGraphSONTranslatorProvider.java
@@ -213,10 +213,6 @@
         method = "shouldNeverPropagateANoBulkTraverser",
         reason = "Reason requires investigation")
 @Graph.OptOut(
-        test = "org.apache.tinkerpop.gremlin.process.traversal.CoreTraversalTest",
-        method = "shouldNeverPropagateANullValuedTraverser",
-        reason = "Reason requires investigation")
-@Graph.OptOut(
         test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.ReadTest",
         method = "*",
         reason = "read and write tests don't translate locally well because of calling iterate() inside read()/write() add a none()")
diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/io/gryo/TinkerGraphGryoTranslatorProvider.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/io/gryo/TinkerGraphGryoTranslatorProvider.java
index d6d93a0..0d30df9 100644
--- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/io/gryo/TinkerGraphGryoTranslatorProvider.java
+++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/io/gryo/TinkerGraphGryoTranslatorProvider.java
@@ -209,10 +209,6 @@
         method = "shouldNeverPropagateANoBulkTraverser",
         reason = "Reason requires investigation")
 @Graph.OptOut(
-        test = "org.apache.tinkerpop.gremlin.process.traversal.CoreTraversalTest",
-        method = "shouldNeverPropagateANullValuedTraverser",
-        reason = "Reason requires investigation")
-@Graph.OptOut(
         test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.ReadTest",
         method = "*",
         reason = "read and write tests don't translate locally well because of calling iterate() inside read()/write() add a none()")